1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
use anchor_lang::prelude::*;
use hpl_utils::Default;
use std::collections::HashMap;

/// User State Account -
/// This account represents the state of a user on the Solana blockchain.
/// PDA: [ 'user', username ]
/// Category: user_state
#[account]
#[derive(PartialEq, Eq, Debug)]
pub struct User {
    /// Bump value used for PDA.
    pub bump: u8,

    /// Public key of the primary wallet associated with the user.
    pub primary_wallet: Pubkey,

    /// List of public keys representing secondary wallets associated with the user.
    pub secondary_wallets: Vec<Pubkey>,

    /// Username of the user.
    pub username: String,

    /// Full name of the user.
    pub name: String,

    /// User's biography or description.
    pub bio: String,

    /// URL of the user's profile picture (pfp).
    pub pfp: String,
}

/// Default implementation for the `User` struct.
/// It sets default values for each field when creating a new `User` instance.
impl Default for User {
    const LEN: usize = 160 + 8; // base size + 8 align

    /// Sets default values for each field of the `User` struct.
    fn set_defaults(&mut self) {
        self.bump = 0;
        self.primary_wallet = Pubkey::default();
        self.secondary_wallets = vec![];
        self.username = String::from("");
        self.name = String::from("");
        self.bio = String::from("");
        self.pfp = String::from("");
    }
}

/// Account representing a wallet resolver.
/// PDA: [ 'wallet_resolver', wallet ]
/// Category: user_state
#[account]
pub struct WalletResolver {
    /// Bump value used for PDA.
    pub bump: u8,

    /// Public key of the user associated with this wallet resolver.
    pub user: Pubkey,

    /// Public key of the wallet being resolved.
    pub wallet: Pubkey,
}

/// Default implementation for the `WalletResolver` struct.
/// It sets default values for each field when creating a new `WalletResolver` instance.
impl Default for WalletResolver {
    const LEN: usize = 65 + 8; // base size + 8 align

    /// Sets default values for each field of the `WalletResolver` struct.
    fn set_defaults(&mut self) {
        self.bump = 0;
        self.user = Pubkey::default();
        self.wallet = Pubkey::default();
    }
}

/// Account representing user profile information.
/// This account stores a user's profile data associated with a specific project.
/// PDA: [ 'profile', project, user, identity ]
/// Category: user_state
#[account]
#[derive(PartialEq, Eq, Debug)]
pub struct Profile {
    /// Bump value used for PDA.
    pub bump: u8,

    /// Public key of the project associated with this profile.
    pub project: Pubkey,

    /// Public key of the user associated with this profile.
    pub user: Pubkey,

    /// Identity of the profile, which can be Main, Wallet, or a custom Value.
    pub identity: ProfileIdentity,

    /// HashMap storing profile data as key-value pairs.
    pub data: HashMap<String, ProfileData>,
}

/// Default implementation for the `Profile` struct.
/// It sets default values for each field when creating a new `Profile` instance.
impl Default for Profile {
    const LEN: usize = 96 + 10 + 8; // base size + 8 align

    /// Sets default values for each field of the `Profile` struct.
    fn set_defaults(&mut self) {
        self.bump = 0;
        self.project = Pubkey::default();
        self.user = Pubkey::default();
        self.identity = ProfileIdentity::Main;
        self.data = HashMap::new();
    }
}

/// Enum representing different types of profile identity.
/// A profile can be Main, Wallet, or a custom Value.
#[derive(AnchorSerialize, AnchorDeserialize, Clone, Debug, Eq, PartialEq)]
pub enum ProfileIdentity {
    Main,
    Wallet { key: Pubkey },
    Value { value: String },
}

/// Implementation for the `ProfileIdentity` enum.
impl ProfileIdentity {
    /// Converts the `ProfileIdentity` enum to bytes.
    pub fn to_bytes(&self) -> Vec<u8> {
        match self {
            ProfileIdentity::Main => {
                let value = String::from("main");
                value.as_bytes().to_vec()
            }
            ProfileIdentity::Wallet { key } => key.as_ref().to_vec(),
            ProfileIdentity::Value { value } => value.as_bytes().to_vec(),
        }
    }

    /// Converts the `ProfileIdentity` enum to a string representation.
    pub fn to_string(&self) -> String {
        match self {
            ProfileIdentity::Main => String::from("main"),
            ProfileIdentity::Wallet { key } => key.to_string(),
            ProfileIdentity::Value { value } => value.clone(),
        }
    }
}

/// Enum representing different types of profile data.
/// Profile data can be a SingleValue, MultiValue, or an Entity represented by a merkle tree.
#[derive(AnchorSerialize, AnchorDeserialize, Clone, Eq, Debug, PartialEq)]
pub enum ProfileData {
    SingleValue { value: String },
    MultiValue { value: Vec<String> },
    Entity { tree: Pubkey },
}

/// Implementation for the `ProfileData` enum.
impl ProfileData {
    /// Length of the `ProfileData` enum in bytes.
    pub const LEN: usize = 8 + 40;
}