usersig/
lib.rs

1#![forbid(unsafe_code)]
2#![forbid(clippy::integer_arithmetic)]
3#![deny(clippy::all)]
4#![allow(clippy::result_large_err)]
5
6use anchor_lang::prelude::*;
7use sgraph::{
8    program::Graph, spl_account_compression::program::SplAccountCompression,
9    spl_account_compression::Noop, AddRelationParams, Controller, InitializeProviderParams,
10    Provider, CONTROLLER_SEED,
11};
12
13#[cfg(not(feature = "no-entrypoint"))]
14use solana_security_txt::security_txt;
15
16declare_id!("s1gsZrDJAXNYSCRhQZk5X3mYyBjAmaVBTYnNhCzj8t2");
17
18#[program]
19pub mod usersig {
20    use super::*;
21
22    /// one time provider permissionless initialization
23    pub fn initialize(ctx: Context<Initialize>) -> Result<()> {
24        const NAME: &str = "User manual signature relations";
25        const WEBSITE: &str = "https://example.com/docs";
26
27        let params = InitializeProviderParams {
28            authority: ctx.accounts.provider.key(),
29            name: NAME.to_owned(),
30            website: WEBSITE.to_owned(),
31        };
32
33        let (_, bump) = Pubkey::find_program_address(&[b"provider"], &ID);
34
35        let signer_seeds: &[&[&[u8]]] = &[&[b"provider", &[bump]]];
36
37        let ctx = ctx
38            .accounts
39            .initialize_provider_ctx()
40            .with_signer(signer_seeds);
41
42        sgraph::cpi::initialize_provider(ctx, params)?;
43
44        Ok(())
45    }
46
47    /// sign_relation adds relation when user signs the transaction
48    pub fn sign_relation(ctx: Context<SignRelation>, to: Pubkey) -> Result<()> {
49        let params = AddRelationParams {
50            from: ctx.accounts.from.key(),
51            to,
52            extra: vec![], // would love to see usecase for this
53        };
54
55        let (_, bump) = Pubkey::find_program_address(&[b"provider"], &ID);
56        let signer_seeds: &[&[&[u8]]] = &[&[b"provider", &[bump]]];
57
58        let ctx = ctx.accounts.add_relation_ctx().with_signer(signer_seeds);
59        sgraph::cpi::add_relation(ctx, params)?;
60
61        Ok(())
62    }
63}
64
65#[derive(Accounts)]
66pub struct Initialize<'info> {
67    /// CHECK: seeds are checked
68    #[account(mut, seeds = [b"provider"], bump)]
69    pub provider: AccountInfo<'info>,
70
71    #[account(mut)]
72    pub payer: Signer<'info>,
73    pub graph_program: Program<'info, Graph>,
74    pub system_program: Program<'info, System>,
75}
76
77impl<'info> Initialize<'info> {
78    pub fn initialize_provider_ctx(
79        &self,
80    ) -> CpiContext<'_, '_, '_, 'info, sgraph::cpi::accounts::InitializeProvider<'info>> {
81        let cpi_program = self.graph_program.to_account_info();
82        let cpi_accounts = sgraph::cpi::accounts::InitializeProvider {
83            payer: self.payer.to_account_info(),
84            provider: self.provider.to_account_info(),
85            system_program: self.system_program.to_account_info(),
86        };
87        CpiContext::new(cpi_program, cpi_accounts)
88    }
89}
90
91#[derive(Accounts)]
92#[instruction(to: Pubkey)]
93pub struct SignRelation<'info> {
94    pub from: Signer<'info>,
95
96    #[account(mut, seeds = [b"provider"], bump)]
97    pub provider: Account<'info, Provider>,
98
99    /// CHECK: key is checked
100    #[account(mut)]
101    pub tree: AccountInfo<'info>,
102
103    /// CHECK: seeds are checked
104    #[account(
105        seeds = [CONTROLLER_SEED],
106        seeds::program = graph_program.key,
107        bump,
108        has_one = tree,
109    )]
110    pub tree_controller: Account<'info, Controller>,
111
112    #[account(mut)]
113    pub payer: Signer<'info>,
114
115    pub ac_program: Program<'info, SplAccountCompression>,
116    pub noop_program: Program<'info, Noop>,
117    pub graph_program: Program<'info, Graph>,
118}
119
120impl<'info> SignRelation<'info> {
121    pub fn add_relation_ctx(
122        &self,
123    ) -> CpiContext<'_, '_, '_, 'info, sgraph::cpi::accounts::AddRelation<'info>> {
124        let cpi_program = self.graph_program.to_account_info();
125
126        let cpi_accounts = sgraph::cpi::accounts::AddRelation {
127            provider: self.provider.to_account_info(),
128            authority: self.provider.to_account_info(),
129            tree: self.tree.to_account_info(),
130            tree_controller: self.tree_controller.to_account_info(),
131            payer: self.payer.to_account_info(),
132            ac_program: self.ac_program.to_account_info(),
133            noop_program: self.noop_program.to_account_info(),
134        };
135        CpiContext::new(cpi_program, cpi_accounts)
136    }
137}
138
139#[cfg(not(feature = "no-entrypoint"))]
140security_txt! {
141    name: "sgraph usersig",
142    project_url: "https://sgraph.io",
143    contacts: "email:security@sgraph.io",
144    policy: "Please report (suspected) security vulnerabilities to email above.
145You will receive a response from us within 48 hours.",
146    source_code: "https://github.com/sgraph-protocol/sgraph",
147    source_revision: env!("GIT_HASH"),
148    acknowledgements: "Everyone in the Solana community"
149}