metaplex-foundation / shank

Extracts IDL from Solana Rust contracts
https://docs.rs/crate/shank_macro/latest
116 stars 23 forks source link

Extend shank instructions to work with Instruction struct variants #32

Closed ngundotra closed 2 years ago

ngundotra commented 2 years ago

This PR adds two features to ShankInstructions:

  1. Parses Instruction variants with named arguments
  2. Parses Instruction variants with multiple unnamed arguments (with names instructionArgs0, instructionArgs1, etc)

This is necessary to use Shank with SPL instructions. Closes #33

Example: Instruction variant with named arguments

Instructions with named arguments now works. The following

#[derive(ShankInstruction)]
pub enum Instruction {
    #[account(0, name = "creator", sig)]
    #[account(1, name = "thing", mut)]
    CreateThing {
        some_args: SomeArgs,
        other_args: OtherArgs,
    },
    #[account(0, name = "creator", sig)]
    CloseThing(Option<u8>),
}

compiles to:

{
  "version": "",
  "name": "",
  "instructions": [
    {
      "name": "CreateThing",
      "accounts": [
        {
          "name": "creator",
          "isMut": false,
          "isSigner": true
        },
        {
          "name": "thing",
          "isMut": true,
          "isSigner": false
        }
      ],
      "args": [
        {
          "name": "someArgs",
          "type": {
            "defined": "SomeArgs"
          }
        },
        {
          "name": "otherArgs",
          "type": {
            "defined": "OtherArgs"
          }
        }
      ],
      "discriminant": {
        "type": "u8",
        "value": 0
      }
    },
    {
      "name": "CloseThing",
      "accounts": [
        {
          "name": "creator",
          "isMut": false,
          "isSigner": true
        }
      ],
      "args": [
        {
          "name": "instructionArgs",
          "type": {
            "option": "u8"
          }
        }
      ],
      "discriminant": {
        "type": "u8",
        "value": 1
      }
    }
  ],
  "metadata": {
    "origin": "shank"
  }
}

Example: Instruction variant with multiple unnamed arguments

Previously this would throw with an error saying "An Instruction can only have one arg field". But now it works. The following

#[derive(ShankInstruction)]
pub enum Instruction {
    #[account(0, name = "creator", sig)]
    CloseThing(Option<u8>, ComplexArgs, ComplexArgs),
}

compiles to

{
  "version": "",
  "name": "",
  "instructions": [
    {
      "name": "CloseThing",
      "accounts": [
        {
          "name": "creator",
          "isMut": false,
          "isSigner": true
        }
      ],
      "args": [
        {
          "name": "instructionArgs0",
          "type": {
            "option": "u8"
          }
        },
        {
          "name": "instructionArgs1",
          "type": {
            "defined": "ComplexArgs"
          }
        },
        {
          "name": "instructionArgs2",
          "type": {
            "defined": "ComplexArgs"
          }
        }
      ],
      "discriminant": {
        "type": "u8",
        "value": 0
      }
    }
  ],
  "metadata": {
    "origin": "shank"
  }
}

Todo:

ngundotra commented 2 years ago

Absolutely! Go for it. Thanks Thorsten!