coral-xyz / anchor

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

Anchor IDL different (incorrect?) from Solana Playground IDL generated #2914

Open RyanWilkins opened 5 months ago

RyanWilkins commented 5 months ago

I was following this guide to learn anchor: https://www.quicknode.com/guides/solana-development/anchor/transfer-tokens

When deploying the program via Solana Playground (as instructed), everything runs fine. The issue comes from trying to replicate on my local machine using anchor. The code is exactly the same; however I was running into this issue when trying to invoke the transferLamports function:

    'Program log: Instruction: TransferLamports',
    'Program log: AnchorError caused by account: to. Error Code: ConstraintMut. Error Number: 2000. Error Message: A mut constraint was violated.',

After much, much frustration I discovered that the issue is with the IDL that Anchor generates when building the program. Comparing to the one that Solana Playground generates (remember - exact same lib.rs):

Solana Playground

"accounts":[
{"name":"from","isMut":true,"isSigner":true},
{"name":"to","isMut":true,"isSigner":false},
{"name":"systemProgram","isMut":false,"isSigner":false}],
"args":[{"name":"amount","type":"u64"}]}]

Local Anchor

      "accounts": [
        {
          "name": "payer",
          "writable": true,
          "signer": true
        },
        {
          "name": "recipient",
          "writable": true
        },
        {
          "name": "system_program",
          "address": "11111111111111111111111111111111"
        }
      ],
      "args": [
        {
          "name": "amount",
          "type": "u64"
        }
      ]

Pulling down the IDL from Solana Playground and using that in my Typescript module instead allows the code to run just fine.

    const sig = program.methods.transferLamports(new BN(10000)).accounts({
        from: from.publicKey,
        to: to.publicKey,
        system_program: system_program
    })

What is causing anchor to produce a completely different IDL type that isn't compatible with anchor itself?

acheroncrypto commented 5 months ago

This is because the IDL has been rewritten, and it's incompatible with the old IDL.

There is also a new release (v0.30.0) which was released 2 days ago. Solana Playground has not yet upgraded to the latest version, so if you use the IDL generated from there (or any other place), you can use the 0.29.0 version of @coral-xyz/anchor locally (instead of 0.30.0).

RyanWilkins commented 5 months ago

This is because the IDL has been rewritten, and it's incompatible with the old IDL.

There is also a new release (v0.30.0) which was released 2 days ago. Solana Playground has not yet upgraded to the latest version, so if you use the IDL generated from there (or any other place), you can use the 0.29.0 version of @coral-xyz/anchor locally (instead of 0.30.0).

Hi, appreciate the quick response.

Before I go messing around with all my configuration, can you clarify for me if there is a version of the 'npm' anchor package which can correctly invoke program functions with this new IDL format? Any quick references on syntax?

acheroncrypto commented 5 months ago

Before I go messing around with all my configuration, can you clarify for me if there is a version of the 'npm' anchor package which can correctly invoke program functions with this new IDL format? Any quick references on syntax?

It will work as long as you use the same Anchor version for all tooling (crates, packages, CLI).

See https://www.anchor-lang.com/release-notes/0.30.0#type-script

RyanWilkins commented 5 months ago

Adding extra context for anyone else finding this in the future; not quite there yet:

I've updated everything to the most recent version but now I'm getting an error when the final method .rpc() is called. I've tracked it to the build function in the NamespaceFactory index.js, the issue stems from coder.instruction.encode(ixName, ix):

TypeError: Cannot read properties of undefined (reading 'encode')

I believe this means I've setup my provider wrong? I can't find any changes from 0.26 (the version i had before) and the current version; I did not change any other code. Currently the provider is setup like this:

    const provider = new AnchorProvider(conn, new Wallet(myPK), AnchorProvider.defaultOptions());
    setProvider(provider);

I'm calling the function via

    const sig = await program.methods.transferSol(new BN(10000)).accounts({
        payer: from.publicKey,
        recipient: to.publicKey,
        system_program: system_program
    }).rpc()
acheroncrypto commented 5 months ago

Always use camelCase in TS package : https://www.anchor-lang.com/release-notes/0.30.0#case-conversion

Instead of system_program use systemProgram. It's also not even necessary to specify program accounts in the new version if you get the correct types from target/types and initialize your program with that type.

CryptoCooker commented 5 months ago

How to define program with @coral-xyz/anchor 0.30.0 in typescript?

My current code, which is not working.

import * as splStakingIdl from './idl/spl_staking.json';
const program = new anchor.Program(splStakingIdl, provider);

In version 0.29.0, I used to implement it by this:

import {
  IDL as SplStakingIdl ,
  SplStaking,
} from "./idl/spl_staking";
const program = new anchor.Program(SplStakingIdl as SplStaking, programId, provider);

After upgrading to 0.30.0, anchor doesn't generate IDL in target/types.

Is there any example codebase to integrate program with @coral-xyz/anchor 0.30.0 in typescript?

acheroncrypto commented 5 months ago

All you need is to cast the idl.json's type to the generated camelCased IDL type in target/types. For example:

import * as idl from "./idl/spl_staking.json";
import type { SplStaking } from "./types/spl_staking";

const program = new anchor.Program(idl as unknown as SplStaking, provider);

or

import type { SplStaking } from "./types/spl_staking";

const idl: SplStaking = require("idl/spl_staking.json");
const program = new anchor.Program(idl, provider);
Sidkjr commented 3 months ago

All you need is to cast the idl.json's type to the generated camelCased IDL type in target/types. For example:

import * as idl from "./idl/spl_staking.json";
import type { SplStaking } from "./types/spl_staking";

const program = new anchor.Program(idl as unknown as SplStaking, provider);

or

import type { SplStaking } from "./types/spl_staking";

const idl: SplStaking = require("idl/spl_staking.json");
const program = new anchor.Program(idl, provider);

I tried both of these but they both seem to spew out: Argument of type ' is not assignable to the parameter Idl'.

I'm using crates: anchor-lang "0.30.1", anchor-spl "0.30.1"

and package @coral-xyz/anchor "0.30.1". Does the above method only work for 0.30.0?

It also spews out saying it's missing the name and version properties.

thiruofficalsp commented 3 months ago

I got the missing name and version properties for idl issue as well - still looking for a solution

acheroncrypto commented 3 months ago

@Sidkjr, @thiruofficalsp

If you get ... is not assignable to the parameter Idl error, it means the TS package and the crate/CLI version used to generate the IDL doesn't match.

It's the same if it says missing name and version properties. You'd get this if you used @coral-xyz/anchor 0.29.0 with a new IDL for example.

Sidkjr commented 2 months ago

@acheroncrypto Yep. Got what I was doing wrong.

It's the same if it says missing name and version properties. You'd get this if you used @coral-xyz/anchor 0.29.0 with a new IDL for example.

But eventually decided to revert back to the version of 0.29 for both anchor-lang and anchor-spl crates and it seemed to work perfectly fine.

The old IDL was better😔.

viandwi24 commented 4 weeks ago

same problem, but i need use new anchor version but want to use solanaFM local idl (to help better debugging), so im try to make tools to convert my new idl to old idl, so now can compatible to use in solanaFM

https://github.com/viandwi24/anchor-idl-converter