diff --git a/CHANGELOG.md b/CHANGELOG.md index 7ba87e57..37ad1020 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ incremented for features. * cli: Embed workspace programs into local validator genesis when testing. * cli: Stream program logs to `.anchor/program-logs` directory when testing. +* spl: Add shared memory api. ## [0.2.0] - 2021-02-08 diff --git a/spl/Cargo.toml b/spl/Cargo.toml index 639cedfa..d7b68ed2 100644 --- a/spl/Cargo.toml +++ b/spl/Cargo.toml @@ -9,3 +9,4 @@ description = "CPI clients for SPL programs" [dependencies] anchor-lang = { path = "../lang", version = "0.2.0", features = ["derive"] } spl-token = { version = "3.0.1", features = ["no-entrypoint"] } +solana-program = "=1.5.0" \ No newline at end of file diff --git a/spl/src/lib.rs b/spl/src/lib.rs index 79c66ba6..e5c4fadf 100644 --- a/spl/src/lib.rs +++ b/spl/src/lib.rs @@ -1 +1,2 @@ +pub mod shmem; pub mod token; diff --git a/spl/src/shmem.rs b/spl/src/shmem.rs new file mode 100644 index 00000000..8e7a6b8f --- /dev/null +++ b/spl/src/shmem.rs @@ -0,0 +1,49 @@ +//! CPI API for interacting with the SPL shared memory +//! [program](https://github.com/solana-labs/solana-program-library/tree/master/shared-memory). + +use anchor_lang::{Accounts, CpiContext}; +use solana_program::account_info::AccountInfo; +use solana_program::declare_id; +use solana_program::entrypoint::ProgramResult; +use solana_program::instruction::{AccountMeta, Instruction}; +use solana_program::program; + +// TODO: update this once the final shared memory program gets released. +// shmem4EWT2sPdVGvTZCzXXRAURL9G5vpPxNwSeKhHUL. +declare_id!("DynWy94wrWp5RimU49creYMQ5py3Up8BBNS4VA73VCpi"); + +/// `ret` writes the given `data` field to the shared memory account +/// acting as a return value that can be used across CPI. +/// The caleee should use this to write data into the shared memory account. +/// The caler should use the account directly to pull out and interpret the +/// bytes. Shared memory serialization is not specified and is up to the +/// caller and callee. +pub fn ret<'a, 'b, 'c, 'info>( + ctx: CpiContext<'a, 'b, 'c, 'info, Ret<'info>>, + data: Vec, +) -> ProgramResult { + let instruction = Instruction { + program_id: *ctx.program.key, + accounts: vec![AccountMeta::new(*ctx.accounts.buffer.key, false)], + data, + }; + let mut accounts = vec![ctx.accounts.buffer]; + accounts.push(ctx.program.clone()); + program::invoke(&instruction, &accounts) +} + +#[derive(Accounts)] +pub struct Ret<'info> { + #[account(mut)] + pub buffer: AccountInfo<'info>, +} + +// A set of accounts that can be used with shared memory. +#[derive(Accounts)] +pub struct Shmem<'info> { + // Shared memory account to write the return value into. + #[account(mut, "shmem.owner == shmem_program.key")] + pub shmem: AccountInfo<'info>, + #[account("shmem_program.key == &ID")] + pub shmem_program: AccountInfo<'info>, +}