use crate::shared::{OrderBookId, PubkeyStr};
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize, Serializer};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AdminNonceResponse {
pub nonce: String,
pub message: String,
}
#[derive(Debug, Clone, Serialize)]
pub struct AdminLoginRequest {
pub message: String,
pub signature_bs58: String,
pub pubkey_bytes: Vec<u8>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct AdminLoginResponse {
pub wallet_address: String,
pub expires_at: i64,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct UnifiedMetadataRequest {
#[serde(default)]
pub markets: Vec<MarketMetadataPayload>,
#[serde(default)]
pub outcomes: Vec<OutcomeMetadataPayload>,
#[serde(default)]
pub conditional_tokens: Vec<ConditionalTokenMetadataPayload>,
#[serde(default)]
pub deposit_tokens: Vec<DepositTokenMetadataPayload>,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct MarketMetadataPayload {
pub market_id: i64,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub market_name: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub slug: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub definition: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub banner_image_url_low: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub banner_image_url_medium: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub banner_image_url_high: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub icon_url_low: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub icon_url_medium: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub icon_url_high: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub category: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub subcategory: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub tags: Option<Vec<String>>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub featured_rank: Option<i16>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub metadata_uri: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub s3_synced: Option<bool>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub s3_synced_at: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub s3_error: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct OutcomeMetadataPayload {
pub market_id: i64,
pub outcome_index: i16,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub name_long: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub icon_url_low: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub icon_url_medium: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub icon_url_high: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub metadata_uri: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub s3_synced: Option<bool>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub s3_synced_at: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub s3_error: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ConditionalTokenMetadataPayload {
pub conditional_mint_id: i32,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub outcome_index: Option<i16>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub outcome: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub deposit_symbol: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub short_symbol: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub icon_url_low: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub icon_url_medium: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub icon_url_high: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub metadata_uri: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub decimals: Option<i16>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub s3_synced: Option<bool>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub s3_synced_at: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub s3_error: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DepositTokenMetadataPayload {
pub deposit_asset: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub display_name: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub symbol: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub token_symbol: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub icon_url_low: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub icon_url_medium: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub icon_url_high: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub metadata_uri: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub decimals: Option<i16>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub s3_synced: Option<bool>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub s3_synced_at: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub s3_error: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UnifiedMetadataResponse {
#[serde(default)]
pub markets: Vec<serde_json::Value>,
#[serde(default)]
pub outcomes: Vec<serde_json::Value>,
#[serde(default)]
pub conditional_tokens: Vec<serde_json::Value>,
#[serde(default)]
pub deposit_tokens: Vec<serde_json::Value>,
}
#[derive(Debug, Clone, Serialize)]
#[serde(untagged)]
pub enum TargetSpec {
All(AllTarget),
ById { user_id: String },
ByWallet { wallet_address: String },
ByCode { code: String },
ByBatch { batch_id: String },
}
impl TargetSpec {
pub fn all() -> Self {
Self::All(AllTarget)
}
pub fn user_id(id: impl Into<String>) -> Self {
Self::ById { user_id: id.into() }
}
pub fn wallet_address(addr: impl Into<String>) -> Self {
Self::ByWallet {
wallet_address: addr.into(),
}
}
pub fn code(code: impl Into<String>) -> Self {
Self::ByCode { code: code.into() }
}
pub fn batch_id(id: impl Into<String>) -> Self {
Self::ByBatch {
batch_id: id.into(),
}
}
}
#[derive(Debug, Clone)]
pub struct AllTarget;
impl Serialize for AllTarget {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
serializer.serialize_str("all")
}
}
#[derive(Debug, Clone, Serialize)]
pub struct AllocateCodesRequest {
pub target: TargetSpec,
#[serde(skip_serializing_if = "Option::is_none")]
pub batch_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub vanity_codes: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub count: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub max_uses: Option<i32>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct AllocateCodesResponse {
pub status: String,
#[serde(default)]
pub users_count: Option<u32>,
#[serde(default)]
pub codes_allocated: Option<u32>,
#[serde(default)]
pub user_id: Option<String>,
#[serde(default)]
pub codes: Option<Vec<String>>,
}
#[derive(Debug, Clone, Serialize)]
pub struct WhitelistRequest {
pub wallet_addresses: Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub allocate_codes: Option<bool>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct WhitelistResponse {
pub status: String,
pub wallets_added: u32,
pub codes_allocated: u32,
}
#[derive(Debug, Clone, Serialize)]
pub struct RevokeRequest {
pub target: TargetSpec,
#[serde(skip_serializing_if = "Option::is_none")]
pub reason: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct RevokeResponse {
pub revoked_count: u32,
pub user_ids: Vec<String>,
}
#[derive(Debug, Clone, Serialize)]
pub struct UnrevokeRequest {
pub target: TargetSpec,
}
#[derive(Debug, Clone, Deserialize)]
pub struct UnrevokeResponse {
pub restored_count: u32,
pub user_ids: Vec<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CreateNotificationRequest {
pub title: String,
pub message: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub expires_at: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct CreateNotificationResponse {
pub status: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DismissNotificationRequest {
pub notification_id: String,
}
#[derive(Debug, Clone, Deserialize)]
pub struct DismissNotificationResponse {
pub status: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ReferralConfig {
pub default_code_count: i32,
pub updated_at: DateTime<Utc>,
}
#[derive(Debug, Clone, Default, Serialize)]
pub struct UpdateConfigRequest {
#[serde(skip_serializing_if = "Option::is_none")]
pub default_code_count: Option<i32>,
}
#[derive(Debug, Clone, Default, Serialize)]
pub struct ListCodesRequest {
#[serde(skip_serializing_if = "Option::is_none")]
pub owner_user_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub batch_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub code: Option<String>,
pub limit: u32,
pub offset: u32,
}
#[derive(Debug, Clone, Deserialize)]
pub struct ListCodesResponse {
pub codes: Vec<CodeListEntry>,
pub count: usize,
}
#[derive(Debug, Clone, Deserialize)]
pub struct CodeListEntry {
pub code: String,
pub owner_user_id: String,
pub batch_id: String,
pub is_vanity: bool,
pub max_uses: i32,
pub use_count: i64,
pub created_at: DateTime<Utc>,
}
#[derive(Debug, Clone, Serialize)]
pub struct UpdateCodeRequest {
pub code: String,
pub max_uses: i32,
}
#[derive(Debug, Clone, Deserialize)]
pub struct UpdateCodeResponse {
pub status: String,
pub code: String,
pub max_uses: i32,
}
#[derive(Debug, Clone, Default, Serialize)]
pub struct AdminLogEventsQuery {
#[serde(skip_serializing_if = "Option::is_none")]
pub from_ms: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub to_ms: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub service_name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub environment: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub category: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub severity: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub component: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub operation: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub fingerprint: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub response_status: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub user_visible: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub request_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub user_pubkey: Option<PubkeyStr>,
#[serde(skip_serializing_if = "Option::is_none")]
pub market_pubkey: Option<PubkeyStr>,
#[serde(skip_serializing_if = "Option::is_none")]
pub orderbook_id: Option<OrderBookId>,
#[serde(skip_serializing_if = "Option::is_none")]
pub order_hash: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub trigger_order_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub tx_signature: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub checkpoint_signature: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub limit: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub cursor: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct AdminLogEventsResponse {
pub events: Vec<AdminLogEvent>,
#[serde(default)]
pub next_cursor: Option<String>,
pub limit: u32,
}
#[derive(Debug, Clone, Deserialize)]
pub struct AdminLogEvent {
pub id: i64,
pub public_id: String,
pub service_name: String,
pub environment: String,
pub component: String,
pub operation: String,
pub category: String,
pub severity: String,
pub occurred_at_ms: i64,
#[serde(default)]
pub occurred_at: Option<String>,
pub created_at_ms: i64,
#[serde(default)]
pub created_at: Option<String>,
pub user_visible: bool,
#[serde(default)]
pub request_id: Option<String>,
#[serde(default)]
pub user_pubkey: Option<PubkeyStr>,
#[serde(default)]
pub market_pubkey: Option<PubkeyStr>,
#[serde(default)]
pub orderbook_id: Option<OrderBookId>,
#[serde(default)]
pub order_hash: Option<String>,
#[serde(default)]
pub trigger_order_id: Option<String>,
#[serde(default)]
pub tx_signature: Option<String>,
#[serde(default)]
pub checkpoint_signature: Option<String>,
#[serde(default)]
pub http_status: Option<i32>,
#[serde(default)]
pub grpc_code: Option<String>,
pub message: String,
#[serde(default)]
pub fingerprint: Option<String>,
#[serde(default)]
pub response_status: Option<String>,
pub context: serde_json::Value,
}
#[derive(Debug, Clone, Default, Serialize)]
pub struct AdminLogMetricsQuery {
#[serde(skip_serializing_if = "Option::is_none")]
pub windows: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub scopes: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub limit_per_scope: Option<u32>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct AdminLogMetricsResponse {
#[serde(default)]
pub computed_at: Option<String>,
pub computed_at_ms: i64,
pub breakdowns: Vec<AdminLogMetricBreakdown>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct AdminLogMetricBreakdown {
pub window: String,
pub scope: String,
pub rows: Vec<AdminLogMetricSummary>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct AdminLogMetricSummary {
pub scope_key: String,
pub total_count: u64,
pub error_count: u64,
pub critical_count: u64,
pub user_visible_count: u64,
pub computed_at_ms: i64,
#[serde(default)]
pub computed_at: Option<String>,
}
#[derive(Debug, Clone, Serialize)]
pub struct AdminLogMetricHistoryQuery {
pub scope: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub scope_key: Option<String>,
pub resolution: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub from_ms: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub to_ms: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub limit: Option<u32>,
}
impl AdminLogMetricHistoryQuery {
pub fn new(scope: impl Into<String>) -> Self {
Self {
scope: scope.into(),
scope_key: None,
resolution: "1h".to_string(),
from_ms: None,
to_ms: None,
limit: None,
}
}
}
#[derive(Debug, Clone, Deserialize)]
pub struct AdminLogMetricHistoryResponse {
pub scope: String,
pub scope_key: String,
pub resolution: String,
pub from_ms: i64,
pub to_ms: i64,
#[serde(default)]
pub from: Option<String>,
#[serde(default)]
pub to: Option<String>,
pub points: Vec<AdminLogMetricPoint>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct AdminLogMetricPoint {
pub bucket_start_ms: i64,
#[serde(default)]
pub bucket_start: Option<String>,
pub total_count: u64,
pub error_count: u64,
pub critical_count: u64,
pub user_visible_count: u64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UploadMarketDeploymentAssetsRequest {
pub market_id: i64,
pub market_pubkey: String,
pub market: MarketDeploymentMarket,
#[serde(default)]
pub outcomes: Vec<MarketDeploymentOutcome>,
#[serde(default)]
pub deposit_assets: Vec<MarketDeploymentDepositAsset>,
#[serde(default)]
pub conditional_tokens: Vec<MarketDeploymentConditionalToken>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MarketDeploymentMarket {
pub name: String,
pub slug: String,
#[serde(default)]
pub description: Option<String>,
#[serde(default)]
pub definition: Option<String>,
#[serde(default)]
pub banner_image_url_low: Option<String>,
#[serde(default)]
pub banner_image_url_medium: Option<String>,
#[serde(default)]
pub banner_image_url_high: Option<String>,
#[serde(default)]
pub icon_url_low: Option<String>,
#[serde(default)]
pub icon_url_medium: Option<String>,
#[serde(default)]
pub icon_url_high: Option<String>,
#[serde(default)]
pub category: Option<String>,
#[serde(default)]
pub subcategory: Option<String>,
#[serde(default)]
pub tags: Vec<String>,
#[serde(default)]
pub featured_rank: Option<i32>,
#[serde(default)]
pub banner_image_data_url_low: Option<String>,
#[serde(default)]
pub banner_image_content_type_low: Option<String>,
#[serde(default)]
pub banner_image_data_url_medium: Option<String>,
#[serde(default)]
pub banner_image_content_type_medium: Option<String>,
#[serde(default)]
pub banner_image_data_url_high: Option<String>,
#[serde(default)]
pub banner_image_content_type_high: Option<String>,
#[serde(default)]
pub icon_image_data_url_low: Option<String>,
#[serde(default)]
pub icon_image_content_type_low: Option<String>,
#[serde(default)]
pub icon_image_data_url_medium: Option<String>,
#[serde(default)]
pub icon_image_content_type_medium: Option<String>,
#[serde(default)]
pub icon_image_data_url_high: Option<String>,
#[serde(default)]
pub icon_image_content_type_high: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MarketDeploymentOutcome {
pub index: i32,
pub name: String,
pub symbol: String,
#[serde(default)]
pub description: Option<String>,
#[serde(default)]
pub icon_url_low: Option<String>,
#[serde(default)]
pub icon_url_medium: Option<String>,
#[serde(default)]
pub icon_url_high: Option<String>,
#[serde(default)]
pub icon_image_data_url_low: Option<String>,
#[serde(default)]
pub icon_image_content_type_low: Option<String>,
#[serde(default)]
pub icon_image_data_url_medium: Option<String>,
#[serde(default)]
pub icon_image_content_type_medium: Option<String>,
#[serde(default)]
pub icon_image_data_url_high: Option<String>,
#[serde(default)]
pub icon_image_content_type_high: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MarketDeploymentDepositAsset {
pub mint: String,
pub display_name: String,
pub symbol: String,
#[serde(default)]
pub description: Option<String>,
#[serde(default)]
pub icon_url_low: Option<String>,
#[serde(default)]
pub icon_url_medium: Option<String>,
#[serde(default)]
pub icon_url_high: Option<String>,
pub decimals: i32,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MarketDeploymentConditionalToken {
pub outcome_index: i32,
pub deposit_mint: String,
pub conditional_mint: String,
pub name: String,
pub symbol: String,
#[serde(default)]
pub description: Option<String>,
#[serde(default)]
pub image_data_url_low: Option<String>,
#[serde(default)]
pub image_content_type_low: Option<String>,
#[serde(default)]
pub image_data_url_medium: Option<String>,
#[serde(default)]
pub image_content_type_medium: Option<String>,
pub image_data_url_high: String,
pub image_content_type_high: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UploadMarketDeploymentAssetsResponse {
pub market_metadata_uri: String,
pub market: UploadedMarketImages,
#[serde(default)]
pub outcomes: Vec<UploadedOutcomeImages>,
#[serde(default)]
pub deposit_assets: Vec<UploadedDepositAssetImages>,
#[serde(default)]
pub tokens: Vec<UploadedConditionalToken>,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct UploadedMarketImages {
#[serde(default)]
pub banner_image_url_low: Option<String>,
#[serde(default)]
pub banner_image_url_medium: Option<String>,
#[serde(default)]
pub banner_image_url_high: Option<String>,
#[serde(default)]
pub icon_url_low: Option<String>,
#[serde(default)]
pub icon_url_medium: Option<String>,
#[serde(default)]
pub icon_url_high: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UploadedOutcomeImages {
pub index: i32,
#[serde(default)]
pub icon_url_low: Option<String>,
#[serde(default)]
pub icon_url_medium: Option<String>,
#[serde(default)]
pub icon_url_high: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UploadedDepositAssetImages {
pub mint: String,
#[serde(default)]
pub icon_url_low: Option<String>,
#[serde(default)]
pub icon_url_medium: Option<String>,
#[serde(default)]
pub icon_url_high: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UploadedConditionalToken {
pub conditional_mint: String,
pub metadata_uri: String,
#[serde(default)]
pub image_url_low: Option<String>,
#[serde(default)]
pub image_url_medium: Option<String>,
#[serde(default)]
pub image_url_high: Option<String>,
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::{json, Value};
#[test]
fn upload_market_deployment_assets_request_uses_quality_specific_upload_fields() {
let request: UploadMarketDeploymentAssetsRequest = serde_json::from_value(json!({
"market_id": 7,
"market_pubkey": "market-pubkey",
"market": {
"name": "Market",
"slug": "market",
"banner_image_data_url_high": "data:image/webp;base64,banner-high",
"banner_image_content_type_high": "image/webp",
"icon_image_data_url_low": "data:image/webp;base64,icon-low",
"icon_image_content_type_low": "image/webp",
"icon_image_data_url_high": "data:image/webp;base64,icon-high",
"icon_image_content_type_high": "image/webp"
},
"outcomes": [{
"index": 0,
"name": "Yes",
"symbol": "YES",
"icon_image_data_url_high": "data:image/webp;base64,outcome-high",
"icon_image_content_type_high": "image/webp"
}],
"conditional_tokens": [{
"outcome_index": 0,
"deposit_mint": "deposit-mint",
"conditional_mint": "conditional-mint",
"name": "Yes USDC",
"symbol": "YES-USDC",
"image_data_url_low": "data:image/webp;base64,token-low",
"image_content_type_low": "image/webp",
"image_data_url_high": "data:image/webp;base64,token-high",
"image_content_type_high": "image/webp"
}]
}))
.unwrap();
let value = serde_json::to_value(request).unwrap();
let market = value["market"].as_object().unwrap();
assert_eq!(
market
.get("banner_image_data_url_high")
.and_then(Value::as_str),
Some("data:image/webp;base64,banner-high")
);
assert_eq!(
market
.get("icon_image_data_url_low")
.and_then(Value::as_str),
Some("data:image/webp;base64,icon-low")
);
assert!(!market.contains_key("banner_image_data_url"));
assert!(!market.contains_key("icon_image_data_url"));
let outcome = value["outcomes"][0].as_object().unwrap();
assert_eq!(
outcome
.get("icon_image_content_type_high")
.and_then(Value::as_str),
Some("image/webp")
);
assert!(!outcome.contains_key("icon_image_content_type"));
let token = value["conditional_tokens"][0].as_object().unwrap();
assert_eq!(
token.get("image_data_url_high").and_then(Value::as_str),
Some("data:image/webp;base64,token-high")
);
assert!(!token.contains_key("image_data_url"));
assert!(!token.contains_key("image_content_type"));
}
#[test]
fn upload_market_deployment_assets_response_reads_variant_token_urls() {
let response: UploadMarketDeploymentAssetsResponse = serde_json::from_value(json!({
"market_metadata_uri": "s3://metadata/market.json",
"market": {
"banner_image_url_low": "https://cdn/banner-low.webp",
"banner_image_url_medium": "https://cdn/banner-medium.webp",
"banner_image_url_high": "https://cdn/banner-high.webp"
},
"outcomes": [{
"index": 0,
"icon_url_high": "https://cdn/outcome-high.webp"
}],
"deposit_assets": [{
"mint": "deposit-mint",
"icon_url_high": "https://cdn/deposit-high.webp"
}],
"tokens": [{
"conditional_mint": "conditional-mint",
"metadata_uri": "s3://metadata/token.json",
"image_url_low": "https://cdn/token-low.webp",
"image_url_medium": "https://cdn/token-medium.webp",
"image_url_high": "https://cdn/token-high.webp"
}]
}))
.unwrap();
assert_eq!(response.deposit_assets[0].mint, "deposit-mint");
assert_eq!(
response.tokens[0].image_url_high.as_deref(),
Some("https://cdn/token-high.webp")
);
let token = serde_json::to_value(&response.tokens[0]).unwrap();
assert!(token.get("image_url").is_none());
}
}