lang, examples: Remove associated keyword
This commit is contained in:
parent
e5b797b31f
commit
53b44e8fae
|
@ -1,11 +1,5 @@
|
|||
use anchor_lang::prelude::*;
|
||||
|
||||
#[associated]
|
||||
#[derive(Default)]
|
||||
pub struct TestData {
|
||||
pub data: u64,
|
||||
}
|
||||
|
||||
#[account]
|
||||
pub struct Data {
|
||||
pub udata: u128,
|
||||
|
|
|
@ -103,35 +103,6 @@ pub struct TestClose<'info> {
|
|||
sol_dest: AccountInfo<'info>,
|
||||
}
|
||||
|
||||
// `my_account` is the associated token account being created.
|
||||
// `authority` must be a `mut` and `signer` since it will pay for the creation
|
||||
// of the associated token account. `state` is used as an association, i.e., one
|
||||
// can *optionally* identify targets to be used as seeds for the program
|
||||
// derived address by using `with` (and it doesn't have to be a state account).
|
||||
// For example, the SPL token program uses a `Mint` account. Lastly,
|
||||
// `system_program` are *required* by convention, since the account is needed
|
||||
// when creating the associated program address within the program.
|
||||
#[derive(Accounts)]
|
||||
pub struct TestInitAssociatedAccount<'info> {
|
||||
#[account(init, associated = authority, with = state, with = data, with = b"my-seed")]
|
||||
pub my_account: ProgramAccount<'info, TestData>,
|
||||
#[account(mut, signer)]
|
||||
pub authority: AccountInfo<'info>,
|
||||
pub state: ProgramState<'info, MyState>,
|
||||
pub data: ProgramAccount<'info, Data>,
|
||||
pub system_program: AccountInfo<'info>,
|
||||
}
|
||||
|
||||
#[derive(Accounts)]
|
||||
pub struct TestAssociatedAccount<'info> {
|
||||
#[account(mut, associated = authority, with = state, with = data, with = b"my-seed")]
|
||||
pub my_account: ProgramAccount<'info, TestData>,
|
||||
#[account(mut, signer)]
|
||||
pub authority: AccountInfo<'info>,
|
||||
pub state: ProgramState<'info, MyState>,
|
||||
pub data: ProgramAccount<'info, Data>,
|
||||
}
|
||||
|
||||
#[derive(Accounts)]
|
||||
pub struct TestU16<'info> {
|
||||
#[account(init)]
|
||||
|
@ -147,15 +118,6 @@ pub struct TestI16<'info> {
|
|||
#[derive(Accounts)]
|
||||
pub struct TestSimulate {}
|
||||
|
||||
#[derive(Accounts)]
|
||||
pub struct TestSimulateAssociatedAccount<'info> {
|
||||
#[account(init, associated = authority)]
|
||||
pub my_account: ProgramAccount<'info, TestData>,
|
||||
#[account(mut, signer)]
|
||||
pub authority: AccountInfo<'info>,
|
||||
pub system_program: AccountInfo<'info>,
|
||||
}
|
||||
|
||||
#[derive(Accounts)]
|
||||
pub struct TestI8<'info> {
|
||||
#[account(init)]
|
||||
|
|
|
@ -57,22 +57,6 @@ pub mod misc {
|
|||
misc2::cpi::state::set_data(ctx, data)
|
||||
}
|
||||
|
||||
pub fn test_init_associated_account(
|
||||
ctx: Context<TestInitAssociatedAccount>,
|
||||
data: u64,
|
||||
) -> ProgramResult {
|
||||
ctx.accounts.my_account.data = data;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn test_associated_account(
|
||||
ctx: Context<TestAssociatedAccount>,
|
||||
data: u64,
|
||||
) -> ProgramResult {
|
||||
ctx.accounts.my_account.data = data;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn test_u16(ctx: Context<TestU16>, data: u16) -> ProgramResult {
|
||||
ctx.accounts.my_account.data = data;
|
||||
Ok(())
|
||||
|
@ -85,20 +69,6 @@ pub mod misc {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn test_simulate_associated_account(
|
||||
ctx: Context<TestSimulateAssociatedAccount>,
|
||||
data: u32,
|
||||
) -> ProgramResult {
|
||||
let associated_account = *ctx.accounts.my_account.to_account_info().key;
|
||||
emit!(E1 { data });
|
||||
emit!(E2 { data: 1234 });
|
||||
emit!(E3 { data: 9 });
|
||||
emit!(E4 {
|
||||
data: associated_account
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn test_i8(ctx: Context<TestI8>, data: i8) -> ProgramResult {
|
||||
ctx.accounts.data.data = data;
|
||||
Ok(())
|
||||
|
|
|
@ -135,89 +135,6 @@ describe("misc", () => {
|
|||
assert.ok(stateAccount.auth.equals(program.provider.wallet.publicKey));
|
||||
});
|
||||
|
||||
it("Can init an associated program account", async () => {
|
||||
const state = await program.state.address();
|
||||
|
||||
// Manual associated address calculation for test only. Clients should use
|
||||
// the generated methods.
|
||||
const [
|
||||
associatedAccount,
|
||||
nonce,
|
||||
] = await anchor.web3.PublicKey.findProgramAddress(
|
||||
[
|
||||
anchor.utils.bytes.utf8.encode("anchor"),
|
||||
program.provider.wallet.publicKey.toBuffer(),
|
||||
state.toBuffer(),
|
||||
data.publicKey.toBuffer(),
|
||||
anchor.utils.bytes.utf8.encode("my-seed"),
|
||||
],
|
||||
program.programId
|
||||
);
|
||||
await assert.rejects(
|
||||
async () => {
|
||||
await program.account.testData.fetch(associatedAccount);
|
||||
},
|
||||
(err) => {
|
||||
assert.ok(
|
||||
err.toString() ===
|
||||
`Error: Account does not exist ${associatedAccount.toString()}`
|
||||
);
|
||||
return true;
|
||||
}
|
||||
);
|
||||
await program.rpc.testInitAssociatedAccount(new anchor.BN(1234), {
|
||||
accounts: {
|
||||
myAccount: associatedAccount,
|
||||
authority: program.provider.wallet.publicKey,
|
||||
state,
|
||||
data: data.publicKey,
|
||||
rent: anchor.web3.SYSVAR_RENT_PUBKEY,
|
||||
systemProgram: anchor.web3.SystemProgram.programId,
|
||||
},
|
||||
});
|
||||
// Try out the generated associated method.
|
||||
const account = await program.account.testData.associated(
|
||||
program.provider.wallet.publicKey,
|
||||
state,
|
||||
data.publicKey,
|
||||
anchor.utils.bytes.utf8.encode("my-seed")
|
||||
);
|
||||
assert.ok(account.data.toNumber() === 1234);
|
||||
});
|
||||
|
||||
it("Can use an associated program account", async () => {
|
||||
const state = await program.state.address();
|
||||
const [
|
||||
associatedAccount,
|
||||
nonce,
|
||||
] = await anchor.web3.PublicKey.findProgramAddress(
|
||||
[
|
||||
anchor.utils.bytes.utf8.encode("anchor"),
|
||||
program.provider.wallet.publicKey.toBuffer(),
|
||||
state.toBuffer(),
|
||||
data.publicKey.toBuffer(),
|
||||
anchor.utils.bytes.utf8.encode("my-seed"),
|
||||
],
|
||||
program.programId
|
||||
);
|
||||
await program.rpc.testAssociatedAccount(new anchor.BN(5), {
|
||||
accounts: {
|
||||
myAccount: associatedAccount,
|
||||
authority: program.provider.wallet.publicKey,
|
||||
state,
|
||||
data: data.publicKey,
|
||||
},
|
||||
});
|
||||
// Try out the generated associated method.
|
||||
const account = await program.account.testData.associated(
|
||||
program.provider.wallet.publicKey,
|
||||
state,
|
||||
data.publicKey,
|
||||
anchor.utils.bytes.utf8.encode("my-seed")
|
||||
);
|
||||
assert.ok(account.data.toNumber() === 5);
|
||||
});
|
||||
|
||||
it("Can retrieve events when simulating a transaction", async () => {
|
||||
const resp = await program.simulate.testSimulate(44);
|
||||
const expectedRaw = [
|
||||
|
@ -238,55 +155,6 @@ describe("misc", () => {
|
|||
assert.ok(resp.events[2].data.data === 9);
|
||||
});
|
||||
|
||||
it("Can retrieve events when associated account is initialized in simulated transaction", async () => {
|
||||
const myAccount = await program.account.testData.associatedAddress(
|
||||
program.provider.wallet.publicKey
|
||||
);
|
||||
await assert.rejects(
|
||||
async () => {
|
||||
await program.account.testData.fetch(myAccount);
|
||||
},
|
||||
(err) => {
|
||||
assert.ok(
|
||||
err.toString() ===
|
||||
`Error: Account does not exist ${myAccount.toString()}`
|
||||
);
|
||||
return true;
|
||||
}
|
||||
);
|
||||
|
||||
const resp = await program.simulate.testSimulateAssociatedAccount(44, {
|
||||
accounts: {
|
||||
myAccount,
|
||||
authority: program.provider.wallet.publicKey,
|
||||
rent: anchor.web3.SYSVAR_RENT_PUBKEY,
|
||||
systemProgram: anchor.web3.SystemProgram.programId,
|
||||
},
|
||||
});
|
||||
|
||||
const expectedRaw = [
|
||||
"Program Fv6oRfzWETatiMymBvTs1JpRspZz3DbBfjZJEvUTDL1g invoke [1]",
|
||||
"Program 11111111111111111111111111111111 invoke [2]",
|
||||
"Program 11111111111111111111111111111111 success",
|
||||
"Program log: NgyCA9omwbMsAAAA",
|
||||
"Program log: fPhuIELK/k7SBAAA",
|
||||
"Program log: jvbowsvlmkcJAAAA",
|
||||
"Program log: mg+zq/K0sXRV+N/AsG9XLERDZ+J6eQAnnzoQVHlicBQBnGr65KE5Kw==",
|
||||
"Program Fv6oRfzWETatiMymBvTs1JpRspZz3DbBfjZJEvUTDL1g consumed 20460 of 200000 compute units",
|
||||
"Program Fv6oRfzWETatiMymBvTs1JpRspZz3DbBfjZJEvUTDL1g success",
|
||||
];
|
||||
|
||||
assert.ok(JSON.stringify(expectedRaw), resp.raw);
|
||||
assert.ok(resp.events[0].name === "E1");
|
||||
assert.ok(resp.events[0].data.data === 44);
|
||||
assert.ok(resp.events[1].name === "E2");
|
||||
assert.ok(resp.events[1].data.data === 1234);
|
||||
assert.ok(resp.events[2].name === "E3");
|
||||
assert.ok(resp.events[2].data.data === 9);
|
||||
assert.ok(resp.events[3].name === "E4");
|
||||
assert.ok(resp.events[3].data.data.toBase58() === myAccount.toBase58());
|
||||
});
|
||||
|
||||
it("Can use i8 in the idl", async () => {
|
||||
const data = anchor.web3.Keypair.generate();
|
||||
await program.rpc.testI8(-3, {
|
||||
|
|
|
@ -192,78 +192,6 @@ pub fn account(
|
|||
})
|
||||
}
|
||||
|
||||
/// Extends the `#[account]` attribute to allow one to create associated
|
||||
/// accounts. This includes a `Default` implementation, which means all fields
|
||||
/// in an `#[associated]` struct must implement `Default` and an
|
||||
/// `anchor_lang::Bump` trait implementation, which allows the account to be
|
||||
/// used as a program derived address.
|
||||
///
|
||||
/// # Zero Copy Deserialization
|
||||
///
|
||||
/// Similar to the `#[account]` attribute one can enable zero copy
|
||||
/// deserialization by using the `zero_copy` argument:
|
||||
///
|
||||
/// ```ignore
|
||||
/// #[associated(zero_copy)]
|
||||
/// ```
|
||||
///
|
||||
/// For more, see the [`account`](./attr.account.html) attribute.
|
||||
#[proc_macro_attribute]
|
||||
pub fn associated(
|
||||
args: proc_macro::TokenStream,
|
||||
input: proc_macro::TokenStream,
|
||||
) -> proc_macro::TokenStream {
|
||||
let mut account_strct = parse_macro_input!(input as syn::ItemStruct);
|
||||
let account_name = &account_strct.ident;
|
||||
let (impl_gen, ty_gen, where_clause) = account_strct.generics.split_for_impl();
|
||||
|
||||
// Add a `__nonce: u8` field to the struct to hold the bump seed for
|
||||
// the program dervied address.
|
||||
match &mut account_strct.fields {
|
||||
syn::Fields::Named(fields) => {
|
||||
let mut segments = syn::punctuated::Punctuated::new();
|
||||
segments.push(syn::PathSegment {
|
||||
ident: syn::Ident::new("u8", proc_macro2::Span::call_site()),
|
||||
arguments: syn::PathArguments::None,
|
||||
});
|
||||
fields.named.push(syn::Field {
|
||||
attrs: Vec::new(),
|
||||
vis: syn::Visibility::Restricted(syn::VisRestricted {
|
||||
pub_token: syn::token::Pub::default(),
|
||||
paren_token: syn::token::Paren::default(),
|
||||
in_token: None,
|
||||
path: Box::new(parse_quote!(crate)),
|
||||
}),
|
||||
ident: Some(syn::Ident::new("__nonce", proc_macro2::Span::call_site())),
|
||||
colon_token: Some(syn::token::Colon {
|
||||
spans: [proc_macro2::Span::call_site()],
|
||||
}),
|
||||
ty: syn::Type::Path(syn::TypePath {
|
||||
qself: None,
|
||||
path: syn::Path {
|
||||
leading_colon: None,
|
||||
segments,
|
||||
},
|
||||
}),
|
||||
});
|
||||
}
|
||||
_ => panic!("Fields must be named"),
|
||||
}
|
||||
|
||||
let args: proc_macro2::TokenStream = args.into();
|
||||
proc_macro::TokenStream::from(quote! {
|
||||
#[anchor_lang::account(#args)]
|
||||
#account_strct
|
||||
|
||||
#[automatically_derived]
|
||||
impl #impl_gen anchor_lang::Bump for #account_name #ty_gen #where_clause {
|
||||
fn seed(&self) -> u8 {
|
||||
self.__nonce
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[proc_macro_derive(ZeroCopyAccessor, attributes(accessor))]
|
||||
pub fn derive_zero_copy_accessor(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||
let account_strct = parse_macro_input!(item as syn::ItemStruct);
|
||||
|
|
|
@ -56,7 +56,7 @@ pub use crate::program_account::ProgramAccount;
|
|||
pub use crate::state::ProgramState;
|
||||
pub use crate::sysvar::Sysvar;
|
||||
pub use anchor_attribute_access_control::access_control;
|
||||
pub use anchor_attribute_account::{account, associated, zero_copy};
|
||||
pub use anchor_attribute_account::{account, zero_copy};
|
||||
pub use anchor_attribute_error::error;
|
||||
pub use anchor_attribute_event::{emit, event};
|
||||
pub use anchor_attribute_interface::interface;
|
||||
|
@ -233,10 +233,10 @@ impl Key for Pubkey {
|
|||
/// All programs should include it via `anchor_lang::prelude::*;`.
|
||||
pub mod prelude {
|
||||
pub use super::{
|
||||
access_control, account, associated, emit, error, event, interface, program, require,
|
||||
state, zero_copy, AccountDeserialize, AccountSerialize, Accounts, AccountsExit,
|
||||
AccountsInit, AnchorDeserialize, AnchorSerialize, Context, CpiAccount, CpiContext,
|
||||
CpiState, CpiStateContext, Loader, ProgramAccount, ProgramState, Sysvar, ToAccountInfo,
|
||||
access_control, account, emit, error, event, interface, program, require, state, zero_copy,
|
||||
AccountDeserialize, AccountSerialize, Accounts, AccountsExit, AccountsInit,
|
||||
AnchorDeserialize, AnchorSerialize, Context, CpiAccount, CpiContext, CpiState,
|
||||
CpiStateContext, Loader, ProgramAccount, ProgramState, Sysvar, ToAccountInfo,
|
||||
ToAccountInfos, ToAccountMetas,
|
||||
};
|
||||
|
||||
|
@ -307,27 +307,6 @@ pub mod __private {
|
|||
pub const CLOSED_ACCOUNT_DISCRIMINATOR: [u8; 8] = [255, 255, 255, 255, 255, 255, 255, 255];
|
||||
}
|
||||
|
||||
/// Returns the program-derived-address seeds used for creating the associated
|
||||
/// account.
|
||||
#[macro_export]
|
||||
macro_rules! associated_seeds {
|
||||
(account = $pda:expr, associated = $associated:expr) => {
|
||||
&[
|
||||
b"anchor".as_ref(),
|
||||
$associated.to_account_info().key.as_ref(),
|
||||
&[anchor_lang::Bump::seed(&*$pda)],
|
||||
]
|
||||
};
|
||||
(account = $pda:expr, associated = $associated:expr, $(with = $with:expr),+) => {
|
||||
&[
|
||||
b"anchor".as_ref(),
|
||||
$associated.to_account_info().key.as_ref(),
|
||||
$($with.to_account_info().key.as_ref()),+,
|
||||
&[anchor_lang::Bump::seed(&*$pda)][..],
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
/// Ensures a condition is true, otherwise returns the given error.
|
||||
/// Use this with a custom error type.
|
||||
///
|
||||
|
|
Loading…
Reference in New Issue