1use crate::errors::GumError;
2use crate::state::{Connection, Profile, User};
3use anchor_lang::prelude::*;
4use gpl_session::{session_auth_or, Session, SessionError, SessionToken};
5use std::convert::AsRef;
6
7use crate::constants::*;
8use crate::errors::ConnectionError;
9use crate::events::{ConnectionDeleted, ConnectionNew};
10
11#[derive(Accounts, Session)]
13pub struct CreateConnection<'info> {
14 #[account(
16 init,
17 seeds = [
18 CONNECTION_PREFIX_SEED.as_bytes(),
19 from_profile.key().as_ref(),
20 to_profile.key().as_ref()
21 ],
22 bump,
23 payer = authority,
24 space = Connection::LEN
25 )]
26 pub connection: Account<'info, Connection>,
27 #[account(
28 seeds = [
29 PROFILE_PREFIX_SEED.as_bytes(),
30 from_profile.namespace.as_ref().as_bytes(),
31 from_profile.user.as_ref(),
32 ],
33 bump,
34 has_one = user,
35 )]
36 pub from_profile: Account<'info, Profile>,
37 #[account(
38 seeds = [
39 PROFILE_PREFIX_SEED.as_bytes(),
40 to_profile.namespace.as_ref().as_bytes(),
41 to_profile.user.as_ref(),
42 ],
43 bump,
44 )]
45 pub to_profile: Account<'info, Profile>,
46 #[account(
47 seeds = [
48 USER_PREFIX_SEED.as_bytes(),
49 user.random_hash.as_ref(),
50 ],
51 bump,
52 )]
53 pub user: Account<'info, User>,
54
55 #[session(
56 signer = authority,
57 authority = user.authority.key()
58 )]
59 pub session_token: Option<Account<'info, SessionToken>>,
60
61 #[account(mut)]
62 pub authority: Signer<'info>,
63 pub system_program: Program<'info, System>,
65}
66
67#[session_auth_or(
69 ctx.accounts.user.authority.key() == ctx.accounts.authority.key(),
70 GumError::UnauthorizedSigner
71)]
72pub fn create_connection_handler(ctx: Context<CreateConnection>) -> Result<()> {
73 require_neq!(
75 ctx.accounts.from_profile.key(),
76 ctx.accounts.to_profile.key(),
77 ConnectionError::CannotConnectToSelf
78 );
79
80 let connection = &mut ctx.accounts.connection;
81 connection.from_profile = *ctx.accounts.from_profile.to_account_info().key;
82 connection.to_profile = *ctx.accounts.to_profile.to_account_info().key;
83 emit!(ConnectionNew {
85 connection: *connection.to_account_info().key,
86 user: *ctx.accounts.user.to_account_info().key,
87 from_profile: *ctx.accounts.from_profile.to_account_info().key,
88 to_profile: *ctx.accounts.to_profile.to_account_info().key,
89 timestamp: Clock::get()?.unix_timestamp,
90 });
91
92 Ok(())
93}
94
95#[derive(Accounts, Session)]
97pub struct DeleteConnection<'info> {
98 #[account(
100 mut,
101 seeds = [
102 CONNECTION_PREFIX_SEED.as_bytes(),
103 from_profile.key().as_ref(),
104 to_profile.key().as_ref()
105 ],
106 bump,
107 has_one = from_profile,
108 has_one = to_profile,
109 close = refund_receiver,
110 )]
111 pub connection: Account<'info, Connection>,
112 #[account(
113 seeds = [
114 PROFILE_PREFIX_SEED.as_bytes(),
115 from_profile.namespace.as_ref().as_bytes(),
116 from_profile.user.as_ref(),
117 ],
118 bump,
119 has_one = user,
120 )]
121 pub from_profile: Account<'info, Profile>,
122 #[account(
123 seeds = [
124 PROFILE_PREFIX_SEED.as_bytes(),
125 to_profile.namespace.as_ref().as_bytes(),
126 to_profile.user.as_ref(),
127 ],
128 bump,
129 )]
130 pub to_profile: Account<'info, Profile>,
131 #[account(
132 seeds = [
133 USER_PREFIX_SEED.as_bytes(),
134 user.random_hash.as_ref(),
135 ],
136 bump,
137 )]
138 pub user: Account<'info, User>,
139
140 #[session(
141 signer = authority,
142 authority = user.authority.key()
143 )]
144 pub session_token: Option<Account<'info, SessionToken>>,
145
146 #[account(mut)]
147 pub authority: Signer<'info>,
148
149 #[account(mut, constraint = refund_receiver.key() == user.authority)]
150 pub refund_receiver: SystemAccount<'info>,
151
152 pub system_program: Program<'info, System>,
154}
155
156#[session_auth_or(
158 ctx.accounts.user.authority.key() == ctx.accounts.authority.key(),
159 GumError::UnauthorizedSigner
160)]
161pub fn delete_connection_handler(ctx: Context<DeleteConnection>) -> Result<()> {
162 emit!(ConnectionDeleted {
164 connection: *ctx.accounts.connection.to_account_info().key,
165 user: *ctx.accounts.user.to_account_info().key,
166 from_profile: *ctx.accounts.from_profile.to_account_info().key,
167 to_profile: *ctx.accounts.to_profile.to_account_info().key,
168 timestamp: Clock::get()?.unix_timestamp,
169 });
170 Ok(())
171}