Skip to content

Commit f3c469c

Browse files
committed
✨ Session Keys
1 parent ede6485 commit f3c469c

File tree

15 files changed

+1034
-685
lines changed

15 files changed

+1034
-685
lines changed

clients/bolt-sdk/src/index.ts

+20
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,26 @@ export function FindEntityPda({
7676
)[0];
7777
}
7878

79+
export function FindSessionTokenPda({
80+
targetProgram,
81+
sessionSigner,
82+
authority,
83+
}: {
84+
targetProgram: PublicKey;
85+
sessionSigner: PublicKey;
86+
authority: PublicKey;
87+
}) {
88+
return PublicKey.findProgramAddressSync(
89+
[
90+
Buffer.from("session_token"),
91+
targetProgram.toBytes(),
92+
sessionSigner.toBytes(),
93+
authority.toBytes(),
94+
],
95+
SessionProgram.programId,
96+
)[0];
97+
}
98+
7999
// TODO: seed must be Uint8Array like the other FindPda functions
80100
export function FindComponentPda({
81101
componentId,

clients/bolt-sdk/src/world/transactions.ts

+49
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,14 @@ import {
1111
SerializeArgs,
1212
SYSVAR_INSTRUCTIONS_PUBKEY,
1313
World,
14+
SessionProgram,
15+
FindSessionTokenPda,
1416
} from "../index";
1517
import BN from "bn.js";
1618
import type web3 from "@solana/web3.js";
1719
import {
1820
type Connection,
21+
Keypair,
1922
type PublicKey,
2023
Transaction,
2124
type TransactionInstruction,
@@ -47,6 +50,49 @@ export async function InitializeRegistry({
4750
};
4851
}
4952

53+
export async function CreateSession({
54+
sessionSigner,
55+
authority,
56+
targetProgram,
57+
topUp,
58+
validity,
59+
}: {
60+
sessionSigner?: Keypair;
61+
authority: PublicKey;
62+
targetProgram: PublicKey;
63+
topUp?: boolean;
64+
validity?: BN;
65+
}): Promise<{
66+
instruction: TransactionInstruction;
67+
transaction: Transaction;
68+
sessionToken: PublicKey;
69+
sessionSigner: Keypair;
70+
}> {
71+
sessionSigner = sessionSigner ?? Keypair.generate();
72+
const sessionToken = FindSessionTokenPda({
73+
targetProgram,
74+
sessionSigner: sessionSigner.publicKey,
75+
authority,
76+
});
77+
topUp = topUp ?? false;
78+
let instruction = await SessionProgram.methods
79+
.createSession(topUp, validity ?? null)
80+
.accounts({
81+
sessionSigner: sessionSigner.publicKey,
82+
authority,
83+
targetProgram,
84+
sessionToken,
85+
})
86+
.instruction();
87+
const transaction = new Transaction().add(instruction);
88+
return {
89+
instruction,
90+
transaction,
91+
sessionToken,
92+
sessionSigner,
93+
};
94+
}
95+
5096
/**
5197
* Create the transaction to Initialize a new world
5298
* @param payer
@@ -438,13 +484,15 @@ export async function ApplySystem({
438484
world,
439485
extraAccounts,
440486
args,
487+
sessionToken,
441488
}: {
442489
authority: PublicKey;
443490
systemId: PublicKey;
444491
entities: ApplySystemEntity[];
445492
world: PublicKey;
446493
extraAccounts?: web3.AccountMeta[];
447494
args?: object;
495+
sessionToken?: PublicKey;
448496
}): Promise<{ instruction: TransactionInstruction; transaction: Transaction }> {
449497
const instruction = await createApplySystemInstruction({
450498
authority,
@@ -453,6 +501,7 @@ export async function ApplySystem({
453501
world,
454502
extraAccounts,
455503
args,
504+
sessionToken,
456505
});
457506
const transaction = new Transaction().add(instruction);
458507
return {

crates/bolt-lang/attribute/bolt-program/src/lib.rs

+12-8
Original file line numberDiff line numberDiff line change
@@ -150,14 +150,18 @@ fn generate_update(component_type: &Type) -> (TokenStream2, TokenStream2) {
150150
pub fn update(ctx: Context<Update>, data: Vec<u8>) -> Result<()> {
151151
// TODO: Should we also check if the session token authority can be the World::id?
152152
if let Some(session_token) = &ctx.accounts.session_token {
153-
let validity_ctx = bolt_lang::session_keys::ValidityChecker {
154-
session_token: session_token.clone(),
155-
session_signer: ctx.accounts.authority.clone(),
156-
authority: ctx.accounts.bolt_component.bolt_metadata.authority.clone(),
157-
target_program: crate::id(),
158-
};
159-
require!(session_token.validate(validity_ctx)?, bolt_lang::session_keys::SessionError::InvalidToken);
160-
require_eq!(ctx.accounts.bolt_component.bolt_metadata.authority, session_token.authority, bolt_lang::session_keys::SessionError::InvalidToken);
153+
if ctx.accounts.bolt_component.bolt_metadata.authority == World::id() {
154+
require!(Clock::get()?.unix_timestamp < session_token.valid_until, bolt_lang::session_keys::SessionError::InvalidToken);
155+
} else {
156+
let validity_ctx = bolt_lang::session_keys::ValidityChecker {
157+
session_token: session_token.clone(),
158+
session_signer: ctx.accounts.authority.clone(),
159+
authority: ctx.accounts.bolt_component.bolt_metadata.authority.clone(),
160+
target_program: crate::id(),
161+
};
162+
require!(session_token.validate(validity_ctx)?, bolt_lang::session_keys::SessionError::InvalidToken);
163+
require_eq!(ctx.accounts.bolt_component.bolt_metadata.authority, session_token.authority, bolt_lang::session_keys::SessionError::InvalidToken);
164+
}
161165
} else {
162166
require!(ctx.accounts.bolt_component.bolt_metadata.authority == World::id() || (ctx.accounts.bolt_component.bolt_metadata.authority == *ctx.accounts.authority.key && ctx.accounts.authority.is_signer), BoltError::InvalidAuthority);
163167
}

scripts/lint.sh

+3-3
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@ SCRIPT_DIR=$(dirname "$0")
33
PROJECT_DIR="$SCRIPT_DIR/.."
44
pushd "$PROJECT_DIR"
55
echo "### Checking formatting..."
6-
cargo fmt -- --check --verbose
6+
cargo fmt -- --verbose
77

88
echo "### Checking clippy..."
9-
cargo clippy -- --deny=warnings
9+
cargo clippy --fix -- --deny=warnings
1010

1111
echo "### Checking yarn lint..."
12-
yarn lint
12+
yarn lint --write
1313
popd

tests/framework.ts

-6
Original file line numberDiff line numberDiff line change
@@ -71,20 +71,14 @@ export class Framework {
7171
entity1Pda: PublicKey;
7272
entity2Pda: PublicKey;
7373
entity4Pda: PublicKey;
74-
entity5Pda: PublicKey;
7574

7675
componentPositionEntity1Pda: PublicKey;
7776
componentVelocityEntity1Pda: PublicKey;
7877

7978
componentPositionEntity4Pda: PublicKey;
80-
componentPositionEntity5Pda: PublicKey;
81-
82-
sessionSigner: Keypair;
83-
sessionToken: PublicKey;
8479

8580
constructor() {
8681
this.secondAuthority = Keypair.generate().publicKey;
87-
this.sessionSigner = Keypair.generate();
8882
this.worldProgram = anchor.workspace.World;
8983
this.exampleComponentPosition = anchor.workspace.Position;
9084
this.exampleComponentVelocity = anchor.workspace.Velocity;

tests/intermediate-level/acceleration.ts

+8-4
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,14 @@ export function acceleration(framework) {
1313
componentId: framework.exampleComponentPosition.programId,
1414
});
1515

16-
await framework.provider.sendAndConfirm(delegateComponent.transaction, [], {
17-
skipPreflight: true,
18-
commitment: "confirmed",
19-
});
16+
await framework.provider.sendAndConfirm(
17+
delegateComponent.transaction,
18+
[],
19+
{
20+
skipPreflight: true,
21+
commitment: "confirmed",
22+
},
23+
);
2024
const acc = await framework.provider.connection.getAccountInfo(
2125
delegateComponent.componentPda,
2226
);

0 commit comments

Comments
 (0)