coral-xyz / anchor

⚓ Solana Sealevel Framework
https://anchor-lang.com
Apache License 2.0
3.69k stars 1.35k forks source link

IDL problem with user defined types #1870

Closed sadeghte closed 3 months ago

sadeghte commented 2 years ago

This is the error that I faced:

IdlError: Type not found: {"name":"ethAddress","type":{"defined":"u256"}}
at Function.fieldLayout (/home/***********/node_modules/@project-serum/anchor/src/coder/borsh/idl.ts:94:19)
at /home/***********/node_modules/@project-serum/anchor/src/coder/borsh/instruction.ts:114:22
at Array.map (<anonymous>)
at /home/***********/node_modules/@project-serum/anchor/src/coder/borsh/instruction.ts:113:38
at Array.map (<anonymous>)
at Function.parseIxLayout (/home/***********/node_modules/@project-serum/anchor/src/coder/borsh/instruction.ts:112:26)
at new BorshInstructionCoder (/home/***********/node_modules/@project-serum/anchor/src/coder/borsh/instruction.ts:47:43)
at new BorshCoder (/home/***********/node_modules/@project-serum/anchor/src/coder/borsh/index.ts:39:24)
at new Program (/home/***********/node_modules/@project-serum/anchor/src/program/index.ts:282:28)
at /home/***********/cli/muon.ts:30:15

lib.rs

#[program]
pub mod my_program {
    use super::*;

    pub fn add_group(ctx: Context<AddGroup>, eth_address: u256) -> Result<()> {
    let storage = &mut ctx.accounts.storage;
    storage.is_valid = true;
    storage.eth_address = eth_address;
    Ok(())
    }
}

types.rs

use borsh::{BorshDeserialize, BorshSerialize};
use spl_math::uint::U256;

#[derive(PartialEq, Default, Clone)]
pub struct u256(pub U256);

impl BorshSerialize for u256 {
    #[inline]
    fn serialize<W: Write>(&self, writer: &mut W) -> Result<(), std::io::Error> {
        let mut bytes: [u8; 32] = [0; 32];
        self.0.to_little_endian(&mut bytes);
        writer.write_all(&bytes)
    }
}

impl BorshDeserialize for u256 {
    #[inline]
    fn deserialize(buf: &mut &[u8]) -> Result<Self, std::io::Error> {
        if buf.is_empty() {
            return Err(std::io::Error::new(
                std::io::ErrorKind::InvalidInput,
                "Unexpected length of input",
            ));
        }
        let res = u256(U256::from_little_endian(&buf[0..32]));
        *buf = &buf[32..];
        Ok(res)
    }
}

instructions.rs

#[derive(Accounts)]
#[instruction(eth_address: u256)]
pub struct AddGroup<'info> {
    #[account(
        init,
        payer = admin,
        space = GroupInfo::space(),
        seeds = [
            b"group-info".as_ref(),
            &eth_address.as_bytes()
        ],
        bump
    )]
    pub storage: Account<'info, GroupInfo>,
    pub admin: Signer<'info>,
    pub rent_program: Sysvar<'info, Rent>,
    pub system_program: Program<'info, System>
}

state.rs

#[account]
#[derive(Default)]
pub struct GroupInfo {
    pub is_valid: bool,
    pub eth_address: u256
}

impl GroupInfo {
    pub fn is_initialized(&self) -> bool {
        !self.eth_address.0.is_zero()
    }

    pub fn space() -> usize {
        8 + 1 + 32
    }
}

idl.json

{
  "version": "0.1.0",
  "name": "my_program",
  "instructions": [
    {
      "name": "addGroup",
      "accounts": [
        {
          "name": "storage",
          "isMut": true,
          "isSigner": false
        },
        {
          "name": "admin",
          "isMut": true,
          "isSigner": true
        },
        {
          "name": "rentProgram",
          "isMut": false,
          "isSigner": false
        },
        {
          "name": "systemProgram",
          "isMut": false,
          "isSigner": false
        }
      ],
      "args": [
        {
          "name": "ethAddress",
          "type": {
            "defined": "u256"
          }
        }
      ]
    }
  ],
  "accounts": [
    {
      "name": "GroupInfo",
      "type": {
        "kind": "struct",
        "fields": [
          {
            "name": "isValid",
            "type": "bool"
          },
          {
            "name": "ethAddress",
            "type": {
              "defined": "u256"
            }
          }
        ]
      }
    }
  ],
  "types": []
}
tomjohn1028 commented 1 year ago

The issue comes from this block.

It seems to only support checking whether structs derive the serialize/deserialize trait implementations. Custom implementations get left behind when defining types.

acheroncrypto commented 3 months ago

It is now possible to define custom types and include it in the IDL after https://github.com/coral-xyz/anchor/pull/2824.

Example:

https://github.com/coral-xyz/anchor/blob/fb7ea68c0de780c5be688b5dadad6f25dd4c45bc/tests/idl/programs/new-idl/src/lib.rs#L397-L448