diff --git a/programs/gpl_session/README.md b/programs/gpl_session/README.md index 82c9a68..223d1aa 100644 --- a/programs/gpl_session/README.md +++ b/programs/gpl_session/README.md @@ -13,13 +13,15 @@ cargo add session-keys --features no-entrypoint # Usage +The latest version uses `SessionTokenV2`. `SessionToken` (V1) is still supported for backwards compatibility — see [V1 usage](#v1-backwards-compatible) below. + 1. Import the dependencies ```rust -use session_keys::{SessionError, SessionToken, session_auth_or, Session}; +use session_keys::{SessionError, SessionTokenV2, session_auth_or, Session}; ``` -2. Derive the `Session` trait on your instruction struct +2. Derive the `Session` trait on your instruction struct. The macro auto-detects V1 vs V2 from the `session_token` field type. ```rust #[derive(Accounts, Session)] @@ -34,7 +36,7 @@ pub struct Instruction<'info> { authority = user.authority.key() )] // Session Tokens are passed as optional accounts - pub session_token: Option>, + pub session_token: Option>, #[account(mut)] pub signer: Signer<'info>, @@ -42,7 +44,7 @@ pub struct Instruction<'info> { } ``` -3. Add the `session_auth_or` macro to your instruction handler with fallback logic on who the instruction should validate the signer when sessions are not present and an appropirate ErrorCode. If you've used `require*!` macros in anchor_lang you already know how this works. +3. Add the `session_auth_or` macro to your instruction handler with fallback logic on who the instruction should validate the signer when sessions are not present and an appropriate ErrorCode. If you've used `require*!` macros in anchor_lang you already know how this works. ```rust #[session_auth_or( @@ -55,6 +57,98 @@ pub fn ix_handler(ctx: Context,) -> Result<()> { ``` -# Example +# V1 (backwards-compatible) + +To keep using `SessionToken` (V1), import `SessionToken` instead of `SessionTokenV2` and use it as the field type: + +```rust +use session_keys::{SessionError, SessionToken, session_auth_or, Session}; + +#[derive(Accounts, Session)] +pub struct Instruction<'info> { + ... + pub session_token: Option>, + ... +} +``` + +`#[derive(Session)]` picks the right trait implementation based on the field type. You can also use `#[derive(SessionV2)]` to require V2 explicitly. + +# Full V2 example + +A complete Anchor instruction using `SessionTokenV2`: + +```rust +use anchor_lang::prelude::*; +use session_keys::{session_auth_or, Session, SessionError, SessionTokenV2}; + +declare_id!("YourProgramID11111111111111111111111111111111"); + +#[program] +pub mod my_program { + use super::*; + + pub fn initialize(ctx: Context) -> Result<()> { + let counter = &mut ctx.accounts.counter; + counter.authority = *ctx.accounts.user.key; + counter.count = 0; + Ok(()) + } + + /// Either the session signer (via SessionTokenV2) or the original authority + /// can call this. If no session token is provided, the fallback check runs. + #[session_auth_or( + ctx.accounts.counter.authority.key() == ctx.accounts.signer.key(), + SessionError::InvalidToken + )] + pub fn increment(ctx: Context) -> Result<()> { + ctx.accounts.counter.count += 1; + Ok(()) + } +} + +#[derive(Accounts)] +pub struct Initialize<'info> { + #[account(mut)] + pub user: Signer<'info>, + #[account( + init, + payer = user, + space = 8 + 32 + 8, + seeds = [b"counter", user.key().as_ref()], + bump, + )] + pub counter: Account<'info, Counter>, + pub system_program: Program<'info, System>, +} + +#[derive(Accounts, Session)] +pub struct Increment<'info> { + #[account(mut)] + pub signer: Signer<'info>, + + #[account( + mut, + seeds = [b"counter", counter.authority.key().as_ref()], + bump, + )] + pub counter: Account<'info, Counter>, + + #[session( + signer = signer, + authority = counter.authority.key() + )] + pub session_token: Option>, +} + +#[account] +pub struct Counter { + pub authority: Pubkey, + pub count: u64, +} +``` + +# More examples -See [KamikazeJoe](https://github.com/magicblock-labs/Kamikaze-Joe) for an example of a game using session-keys. +- [magicblock-engine-examples / session-keys](https://github.com/magicblock-labs/magicblock-engine-examples/tree/main/session-keys) — Anchor counter program using `SessionTokenV2` with the ephemeral rollups SDK, plus tests and a React frontend. +- [KamikazeJoe](https://github.com/magicblock-labs/Kamikaze-Joe) — a game using session-keys.