Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feat] Idl instruction: add create account macro attr #43

Merged
merged 7 commits into from
Jan 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
{
"version": "",
"name": "",
"instructions": [
{
"name": "Create",
"accounts": [
{
"name": "from",
"isMut": true,
"isSigner": true,
"docs": [
"Payer of the transaction"
]
},
{
"name": "to",
"isMut": true,
"isSigner": false,
"docs": [
"The deterministically defined 'state' account being created via `create_account_with_seed`"
]
},
{
"name": "base",
"isMut": false,
"isSigner": false,
"docs": [
"The program-derived-address signing off on the account creation. Seeds = &[] + bump seed."
]
},
{
"name": "systemProgram",
"isMut": false,
"isSigner": false,
"docs": [
"The system program"
]
},
{
"name": "program",
"isMut": false,
"isSigner": false,
"docs": [
"The program whose state is being constructed"
]
}
],
"args": [
{
"name": "dataLen",
"type": "u64"
}
],
"discriminant": {
"type": "u8",
"value": 0
}
},
{
"name": "CreateBuffer",
"accounts": [
{
"name": "buffer",
"isMut": true,
"isSigner": false
},
{
"name": "authority",
"isMut": false,
"isSigner": true
}
],
"args": [],
"discriminant": {
"type": "u8",
"value": 1
}
},
{
"name": "SetBuffer",
"accounts": [
{
"name": "buffer",
"isMut": true,
"isSigner": false,
"docs": [
"The buffer with the new idl data."
]
},
{
"name": "idl",
"isMut": true,
"isSigner": false,
"docs": [
"The idl account to be updated with the buffer's data."
]
},
{
"name": "authority",
"isMut": false,
"isSigner": true
}
],
"args": [],
"discriminant": {
"type": "u8",
"value": 2
}
},
{
"name": "SetAuthority",
"accounts": [
{
"name": "idl",
"isMut": true,
"isSigner": false
},
{
"name": "authority",
"isMut": false,
"isSigner": true
}
],
"args": [
{
"name": "newAuthority",
"type": "publicKey"
}
],
"discriminant": {
"type": "u8",
"value": 3
}
},
{
"name": "Write",
"accounts": [
{
"name": "idl",
"isMut": true,
"isSigner": false
},
{
"name": "authority",
"isMut": false,
"isSigner": true
}
],
"args": [
{
"name": "idlData",
"type": "bytes"
}
],
"discriminant": {
"type": "u8",
"value": 4
}
}
],
"metadata": {
"origin": "shank"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#[derive(ShankInstruction)]
pub enum Instruction {
#[idl_instruction(Create)]
Create,
#[idl_instruction(CreateBuffer)]
CreateBuffer,
#[idl_instruction(SetBuffer)]
SetBuffer,
#[idl_instruction(SetAuthority)]
SetAuthority,
#[idl_instruction(Write)]
Write,
}
21 changes: 21 additions & 0 deletions shank-idl/tests/instructions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,27 @@ fn instruction_from_single_file_with_multiple_args() {
assert_eq!(idl, expected_idl);
}

#[test]
fn instruction_from_single_file_with_idl_instructions() {
let file = fixtures_dir()
.join("single_file")
.join("create_idl_instructions.rs");
let idl = parse_file(file, &ParseIdlConfig::optional_program_address())
.expect("Parsing should not fail")
.expect("File contains IDL");

let expected_idl: Idl = serde_json::from_str(include_str!(
"./fixtures/instructions/single_file/create_idl_instructions.json"
))
.unwrap();

println!("IDL: {}", idl.try_into_json().unwrap());

println!("Expected: {}", expected_idl.try_into_json().unwrap());

assert_eq!(idl, expected_idl);
}

#[test]
fn instruction_from_single_file_with_optional_account() {
let file = fixtures_dir()
Expand Down
49 changes: 20 additions & 29 deletions shank-macro-impl/src/instruction/account_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ use std::convert::TryFrom;

use proc_macro2::Span;
use syn::{
punctuated::Punctuated, Attribute, Error as ParseError, Ident, Lit, Meta,
MetaList, MetaNameValue, NestedMeta, Result as ParseResult, Token,
punctuated::Punctuated, Attribute, Error as ParseError, Ident, Lit, Meta, MetaList,
MetaNameValue, NestedMeta, Result as ParseResult, Token,
};

const IX_ACCOUNT: &str = "account";
Expand Down Expand Up @@ -35,9 +35,7 @@ impl InstructionAccount {
}
}

pub fn from_account_attr(
attr: &Attribute,
) -> ParseResult<InstructionAccount> {
pub fn from_account_attr(attr: &Attribute) -> ParseResult<InstructionAccount> {
let meta = &attr.parse_meta()?;

match meta {
Expand Down Expand Up @@ -75,9 +73,7 @@ impl InstructionAccount {
let mut optional = false;

for meta in nested {
if let Some((ident, name, value)) =
string_assign_from_nested_meta(meta)?
{
if let Some((ident, name, value)) = string_assign_from_nested_meta(meta)? {
// name/desc
match name.as_str() {
"desc" | "description" | "docs" => desc = Some(value),
Expand All @@ -88,14 +84,14 @@ impl InstructionAccount {
))
}
"name" => account_name = Some(value),
_ => return Err(ParseError::new_spanned(
ident,
"Only desc/description or name can be assigned strings",
)),
_ => {
return Err(ParseError::new_spanned(
ident,
"Only desc/description or name can be assigned strings",
))
}
};
} else if let Some((ident, name)) =
identifier_from_nested_meta(meta)
{
} else if let Some((ident, name)) = identifier_from_nested_meta(meta) {
// signer, writable, optional ...
match name.as_str() {
"signer" | "sign" | "sig" | "s" => signer = true,
Expand Down Expand Up @@ -143,9 +139,7 @@ impl InstructionAccount {
desc,
optional,
}),
None => {
Err(ParseError::new_spanned(nested, "Missing account name"))
}
None => Err(ParseError::new_spanned(nested, "Missing account name")),
}
}
}
Expand Down Expand Up @@ -186,14 +180,15 @@ fn string_assign_from_nested_meta(
nested_meta: &NestedMeta,
) -> ParseResult<Option<(Ident, String, String)>> {
match nested_meta {
NestedMeta::Meta(Meta::NameValue(MetaNameValue {
path, lit, ..
})) => {
NestedMeta::Meta(Meta::NameValue(MetaNameValue { path, lit, .. })) => {
let ident = path.get_ident();
if let Some(ident) = ident {
let token = match lit {
let token = match lit {
Lit::Str(lit) => Ok(lit.value()),
_ => Err(ParseError::new_spanned(ident, "#[account(desc)] arg needs to be assigning to a string")),
_ => Err(ParseError::new_spanned(
ident,
"#[account(desc)] arg needs to be assigning to a string",
)),
}?;
Ok(Some((ident.clone(), ident.to_string(), token)))
} else {
Expand All @@ -204,14 +199,10 @@ fn string_assign_from_nested_meta(
}
}

fn identifier_from_nested_meta(
nested_meta: &NestedMeta,
) -> Option<(Ident, String)> {
pub fn identifier_from_nested_meta(nested_meta: &NestedMeta) -> Option<(Ident, String)> {
match nested_meta {
NestedMeta::Meta(meta) => match meta {
Meta::Path(_) => {
meta.path().get_ident().map(|x| (x.clone(), x.to_string()))
}
Meta::Path(_) => meta.path().get_ident().map(|x| (x.clone(), x.to_string())),
// ignore named values and lists
_ => None,
},
Expand Down
Loading