miracle-api 0.6.0

Miracle is a pay2e protocol for sovereign individuals living in Mirascape Horizon.
Documentation
use steel::*;

// ===== SOCIAL MARKETING REWARDS SYSTEM INSTRUCTIONS =====

/// Social claim data for social media engagement rewards.
///
/// This struct contains the data required for claiming social marketing rewards.
/// Social rewards require payment activity in the same epoch and are verified
/// through oracle signatures to prevent gaming.
///
/// ## Data Structure
/// ```rust
/// struct SocialClaimData {
///     post_url: String,               // Social media post URL
///     oracle_signature: [u8; 64],     // Oracle verification signature
///     engagement_score: u32,          // Future: engagement-based rewards
///     post_timestamp: i64,            // When post was made
///     _padding: [u8; 4],              // For future extensibility
/// }
/// ```
///
/// ## Oracle Signature Message Format
/// The oracle must sign a message with this format:
///
/// `epoch:user_pubkey:post_url:engagement_score:post_timestamp`
///
/// Example: `"100:ABC123...:https://twitter.com/user/123:500:1640995200"`
///
/// This format prevents replay attacks by including epoch and user context.
///
/// ## Verification Requirements
/// - Payment activity required in same epoch
/// - Oracle signature verification
/// - Daily limits enforcement
/// - Content requirements (#MiracleRewards, @MiracleProtocol)
///
/// ## Anti-Gaming Measures
/// - Daily limits per user (max 3 posts per day)
/// - Payment requirement ensures real users
/// - Oracle verification prevents fake posts
/// - Content requirements ensure quality engagement
/// - Epoch-specific signatures prevent replay attacks
#[repr(C)]
#[derive(Debug, Clone, Copy, Pod, Zeroable)]
pub struct SocialClaimData {
    /// Social media post URL for verification.
    /// Must contain required hashtags and mentions.
    pub post_url: [u8; 256], // Fixed-size URL field

    /// Oracle signature for post verification.
    /// This signature validates that the post meets requirements.
    pub oracle_signature: [u8; 64],

    /// Timestamp when the post was made.
    /// Used for daily limit calculations and verification.
    pub post_timestamp: [u8; 8], // i64

    /// Engagement score for future tiered rewards.
    /// Currently unused, reserved for future engagement-based rewards.
    pub engagement_score: [u8; 4], // u32

    /// Padding for future extensibility.
    /// Reserved for additional social claim features.
    pub _padding: [u8; 4],
}

impl SocialClaimData {
    /// Deserialize from bytes manually
    pub fn from_bytes(data: &[u8]) -> Result<Self, &'static str> {
        let expected_size = std::mem::size_of::<Self>();
        if data.len() < expected_size {
            return Err("Insufficient data for SocialClaimData");
        }

        let post_url: [u8; 256] = data[0..256].try_into().map_err(|_| "Invalid post_url")?;
        let oracle_signature: [u8; 64] = data[256..320]
            .try_into()
            .map_err(|_| "Invalid oracle_signature")?;
        let post_timestamp: [u8; 8] = data[320..328]
            .try_into()
            .map_err(|_| "Invalid post_timestamp")?;
        let engagement_score: [u8; 4] = data[328..332]
            .try_into()
            .map_err(|_| "Invalid engagement_score")?;
        let _padding: [u8; 4] = data[332..336].try_into().map_err(|_| "Invalid padding")?;

        Ok(Self {
            post_url,
            oracle_signature,
            engagement_score,
            post_timestamp,
            _padding,
        })
    }
}