Skip to content

Commit 9783cdf

Browse files
add config support to compressible macro
1 parent a194292 commit 9783cdf

File tree

17 files changed

+982
-212
lines changed

17 files changed

+982
-212
lines changed
Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
# Example: Using the add_compressible_instructions Macro
2+
3+
This example shows how to use the `add_compressible_instructions` macro to automatically generate compression-related instructions for your Anchor program.
4+
5+
## Basic Setup
6+
7+
```rust
8+
use anchor_lang::prelude::*;
9+
use light_sdk::{
10+
compressible::{CompressionInfo, HasCompressionInfo},
11+
derive_light_cpi_signer, LightDiscriminator, LightHasher,
12+
};
13+
use light_sdk_macros::add_compressible_instructions;
14+
15+
declare_id!("YourProgramId11111111111111111111111111111");
16+
17+
// Define your CPI signer
18+
pub const LIGHT_CPI_SIGNER: CpiSigner =
19+
derive_light_cpi_signer!("YourCpiSignerPubkey11111111111111111111111");
20+
21+
// Apply the macro to your program module
22+
#[add_compressible_instructions(UserRecord, GameSession)]
23+
#[program]
24+
pub mod my_program {
25+
use super::*;
26+
27+
// The macro automatically generates these instructions:
28+
// - create_compression_config (config management)
29+
// - update_compression_config (config management)
30+
// - compress_user_record (compress existing PDA)
31+
// - compress_game_session (compress existing PDA)
32+
// - decompress_multiple_pdas (decompress compressed accounts)
33+
//
34+
// NOTE: create_user_record and create_game_session are NOT generated
35+
// because they typically need custom initialization logic
36+
37+
// You can still add your own custom instructions here
38+
}
39+
```
40+
41+
## Define Your Account Structures
42+
43+
```rust
44+
#[derive(Debug, LightHasher, LightDiscriminator, Default)]
45+
#[account]
46+
pub struct UserRecord {
47+
#[skip] // Skip compression_info from hashing
48+
pub compression_info: CompressionInfo,
49+
#[hash] // Include in hash
50+
pub owner: Pubkey,
51+
#[hash]
52+
pub name: String,
53+
pub score: u64,
54+
}
55+
56+
// Implement the required trait
57+
impl HasCompressionInfo for UserRecord {
58+
fn compression_info(&self) -> &CompressionInfo {
59+
&self.compression_info
60+
}
61+
62+
fn compression_info_mut(&mut self) -> &mut CompressionInfo {
63+
&mut self.compression_info
64+
}
65+
}
66+
```
67+
68+
## Generated Instructions
69+
70+
### 1. Config Management
71+
72+
```typescript
73+
// Create config (only program upgrade authority can call)
74+
await program.methods
75+
.createCompressibleConfig(
76+
100, // compression_delay
77+
rentRecipient,
78+
addressSpace
79+
)
80+
.accounts({
81+
payer: wallet.publicKey,
82+
config: configPda,
83+
programData: programDataPda,
84+
authority: upgradeAuthority,
85+
systemProgram: SystemProgram.programId,
86+
})
87+
.signers([upgradeAuthority])
88+
.rpc();
89+
90+
// Update config
91+
await program.methods
92+
.updateCompressibleConfig(
93+
200, // new_compression_delay (optional)
94+
newRentRecipient, // (optional)
95+
newAddressSpace, // (optional)
96+
newUpdateAuthority // (optional)
97+
)
98+
.accounts({
99+
config: configPda,
100+
authority: configUpdateAuthority,
101+
})
102+
.signers([configUpdateAuthority])
103+
.rpc();
104+
```
105+
106+
### 2. Compress Existing PDA
107+
108+
```typescript
109+
await program.methods
110+
.compressUserRecord(proof, compressedAccountMeta)
111+
.accounts({
112+
user: user.publicKey,
113+
pdaAccount: userRecordPda,
114+
systemProgram: SystemProgram.programId,
115+
config: configPda,
116+
rentRecipient: rentRecipient,
117+
})
118+
.remainingAccounts(lightSystemAccounts)
119+
.signers([user])
120+
.rpc();
121+
```
122+
123+
### 3. Decompress Multiple PDAs
124+
125+
```typescript
126+
const compressedAccounts = [
127+
{
128+
meta: compressedAccountMeta1,
129+
data: { userRecord: userData },
130+
seeds: [Buffer.from("user_record"), user.publicKey.toBuffer()],
131+
},
132+
{
133+
meta: compressedAccountMeta2,
134+
data: { gameSession: gameData },
135+
seeds: [
136+
Buffer.from("game_session"),
137+
sessionId.toArrayLike(Buffer, "le", 8),
138+
],
139+
},
140+
];
141+
142+
await program.methods
143+
.decompressMultiplePdas(
144+
proof,
145+
compressedAccounts,
146+
[userBump, gameBump], // PDA bumps
147+
systemAccountsOffset
148+
)
149+
.accounts({
150+
feePayer: payer.publicKey,
151+
rentPayer: payer.publicKey,
152+
systemProgram: SystemProgram.programId,
153+
})
154+
.remainingAccounts([
155+
...pdaAccounts, // PDAs to decompress into
156+
...lightSystemAccounts, // Light Protocol system accounts
157+
])
158+
.signers([payer])
159+
.rpc();
160+
```
161+
162+
## What You Need to Implement
163+
164+
Since the macro only generates compression-related instructions, you need to implement:
165+
166+
### 1. Create Instructions
167+
168+
Implement your own create instructions for each account type:
169+
170+
```rust
171+
#[derive(Accounts)]
172+
pub struct CreateUserRecord<'info> {
173+
#[account(mut)]
174+
pub user: Signer<'info>,
175+
#[account(
176+
init,
177+
payer = user,
178+
space = 8 + UserRecord::INIT_SPACE,
179+
seeds = [b"user_record", user.key().as_ref()],
180+
bump,
181+
)]
182+
pub user_record: Account<'info, UserRecord>,
183+
pub system_program: Program<'info, System>,
184+
}
185+
186+
pub fn create_user_record(
187+
ctx: Context<CreateUserRecord>,
188+
name: String,
189+
) -> Result<()> {
190+
let user_record = &mut ctx.accounts.user_record;
191+
192+
// Your custom initialization logic here
193+
user_record.compression_info = CompressionInfo::new()?;
194+
user_record.owner = ctx.accounts.user.key();
195+
user_record.name = name;
196+
user_record.score = 0;
197+
198+
Ok(())
199+
}
200+
```
201+
202+
### 2. Update Instructions
203+
204+
Implement update instructions for your account types with your custom business logic.
205+
206+
## Customization
207+
208+
### Custom Seeds
209+
210+
Use custom seeds in your PDA derivation and pass them in the `seeds` parameter when decompressing:
211+
212+
```rust
213+
seeds = [b"custom_prefix", user.key().as_ref(), &session_id.to_le_bytes()]
214+
```
215+
216+
## Best Practices
217+
218+
1. **Create Config Early**: Create the config immediately after program deployment
219+
2. **Use Config Values**: Always use config values instead of hardcoded constants
220+
3. **Validate Rent Recipient**: The macro automatically validates rent recipient matches config
221+
4. **Handle Compression Timing**: Respect the compression delay from config
222+
5. **Batch Operations**: Use decompress_multiple_pdas for efficiency
223+
224+
## Migration from Manual Implementation
225+
226+
If migrating from a manual implementation:
227+
228+
1. Update your account structs to use `CompressionInfo` instead of separate fields
229+
2. Implement the `HasCompressionInfo` trait
230+
3. Replace your manual instructions with the macro
231+
4. Update client code to use the new instruction names

0 commit comments

Comments
 (0)