Code Monkey home page Code Monkey logo

anchor-client-gen's People

Contributors

eoin-betdex avatar khaiilnafis avatar kklas avatar mschneider avatar sol-mocha avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

anchor-client-gen's Issues

Generated client and type-check

When i try to use generated client as npm package/yarn link in my main project where we have pre-commit/pre-build hooks i get type errors from ts type-check on dec. Is there any solution to for that ? (--skipLibCheck will not work on type error).
Zrzut ekranu 2022-08-24 o 13 35 10

Enums don't use the correct discriminator when not in order

#[derive(Debug, TryFromPrimitive, PartialEq, Eq, Clone, Copy)]
#[repr(u16)]
pub enum GlobalConfigOption {
    EmergencyMode = 0,
    ...

    // 100
    ScopeProgramId = 100,
    ScopePriceId = 101,
}

Codegen:

export interface ScopePriceIdJSON {
  kind: "ScopePriceId"
}

export class ScopePriceId {
  static readonly discriminator = 17
  static readonly kind = "ScopePriceId"
  readonly discriminator = 17
  readonly kind = "ScopePriceId"
}

This should be 101, not 17..

fetchMultiple support

It would be great to have fetchMultiple support to allow for efficient fetching of multiple accounts. This functionality is currently supported by the existing dynamic client library within anchor.

How to pass additional `remaining accounts`?

Anchor allows accessing accounts not defined on the Accounts struct through ctx.remaining_accounts. I currently don't see a way to pass these additional accounts in the generated client code cleanly.

Proposal:
Add optional arg to pass additional accounts

export function redeem(args: RedeemArgs, accounts: RedeemAccounts, additionalAccounts?: AccountMeta[]) {...}

Haven't tried it yet, but I believe there's a workaround where the returned TransactionInstruction can be mutated, but this is non-ideal

Empty "/types/index.ts"

I noticed if I run this tool against an IDL with no "types" defined, the resultant /types/index.ts file will empty, which causes import errors in the other files.

I was able to fix the errors by putting export default {}; in /types/index.ts.

Better errors in the generated clients

Return errors with more information from the client. It would be a good idea to have custom classes for each error types but we would have to have them in a separate lib (maybe anchor-client-gen-common) in order to avoid code duplication when there multiple generated clients in the same codebase.

Originally posted by @kklas in #4 (comment)

Support Uint8Array when applicable

Hey @kklas , thank you for your help with the bytes type. I am currently working on a project, where I would like to use this for more data types, specifically:

  1. Vec<u8>
  2. fixed size arrays [u8; 32]

I had a look at the code already and was able to get it to work on a local branch: https://github.com/mschneider/anchor-client-gen/tree/max/uint8array2 but curious to hear your thoughts as this somewhat breaks with the current abstraction of the library on a few levels.

My ideal outcome would be:

  1. always use the right native array type
  2. always verify size when initializing from user input
  3. possibly pad when initializing from too short user input

Let me know what you think about these changes.

Possible to support multiple programs with inter-dependencies?

Apologies if this is a dumb question, let's say I have a project with a few programs:

programs/main
programs/admin
programs/pools

where the accounts, structs, enums, etc are defined in the main program, and referenced as a dependency in the other two. Anchor creates three IDL's. Is it possible to generate a client (or three different clients?) from this structure? Right now I don't think it's possible to expose the structs cross-program.

`kind` of typescript union members should be static

I'd like to branch on variant kind like below, but kind is an instance variable, not static, so the following doesn't work

switch (myEnumValue.kind) {
  case MyEnum.Swap.kind:
    ...
  case MyEnum.LP.kind:
    ...
}

Proposal

export class Swap {
  static readonly discriminator = 0        // <--- make these 2 fields static 
  static readonly kind = "Swap"
  readonly value: SwapValue

  constructor(value: SwapFields) {
    this.value = [new types.SwapInfo({ ...value[0] })]
  }

  toJSON(): SwapJSON {
    return {
      kind: "Swap",
      value: [this.value[0].toJSON()],
    }
  }

  toEncodable() {
    return {
      Swap: {
        _0: types.SwapInfo.toEncodable(this.value[0]),
      },
    }
  }
}

If there's another more idiomatic way of doing this please let me know instead

Simplifying client facing API by removing `connection` parameter

Interested in getting thoughts on dropping the connection parameter, or making it optional. I'm not clear on the use case on being able to target multiple or different connections.

Anchor already provides a global straight-forward way to get the currently configure connection that could be used within the generated clients.

getProvider().connection

This would make the interface of e.g., fetch, cleaner IMO, passing just the address of the account to fetch, and save client authors having to pass around the connection.

  static async fetch(address: PublicKey): Promise<State | null> {
    const c = getProvider().connection
    const info = await c.getAccountInfo(address)

    if (info === null) {
      return null
    }
    if (!info.owner.equals(PROGRAM_ID)) {
      throw new Error("account doesn't belong to this program")
    }

    return this.decode(info.data)
  }

...

const res = await State.fetch(state.publicKey)

noImplicitAny violations in generated code

import { PublicKey, Connection } from "@solana/web3.js"
import BN from "bn.js" // eslint-disable-line @typescript-eslint/no-unused-vars
import * as borsh from "@project-serum/borsh" // eslint-disable-line @typescript-eslint/no-unused-vars
import * as types from "../types" // eslint-disable-line @typescript-eslint/no-unused-vars
import { PROGRAM_ID } from "../programId"

export interface OrderbookInfoFields {
  admin: PublicKey
  length: number
  applesMint: PublicKey
  orangesMint: PublicKey
  bump: number
  closed: boolean
  id: PublicKey
  tradeLog: Array<types.TradeRecordFields>
}

export interface OrderbookInfoJSON {
  admin: string
  length: number
  applesMint: string
  orangesMint: string
  bump: number
  closed: boolean
  id: string
  tradeLog: Array<types.TradeRecordJSON>
}

export class OrderbookInfo {
  readonly admin: PublicKey
  readonly length: number
  readonly applesMint: PublicKey
  readonly orangesMint: PublicKey
  readonly bump: number
  readonly closed: boolean
  readonly id: PublicKey
  readonly tradeLog: Array<types.TradeRecord>

  static readonly discriminator = Buffer.from([
    126, 118, 193, 78, 125, 233, 132, 90,
  ])

  static readonly layout = borsh.struct([
    borsh.publicKey("admin"),
    borsh.u32("length"),
    borsh.publicKey("applesMint"),
    borsh.publicKey("orangesMint"),
    borsh.u8("bump"),
    borsh.bool("closed"),
    borsh.publicKey("id"),
    borsh.vec(types.TradeRecord.layout(), "tradeLog"),
  ])

  constructor(fields: OrderbookInfoFields) {
    this.admin = fields.admin
    this.length = fields.length
    this.applesMint = fields.applesMint
    this.orangesMint = fields.orangesMint
    this.bump = fields.bump
    this.closed = fields.closed
    this.id = fields.id
    this.tradeLog = fields.tradeLog.map(
      (item) => new types.TradeRecord({ ...item })
    )
  }

  static async fetch(
    c: Connection,
    address: PublicKey
  ): Promise<OrderbookInfo | null> {
    const info = await c.getAccountInfo(address)

    if (info === null) {
      return null
    }
    if (!info.owner.equals(PROGRAM_ID)) {
      throw new Error("account doesn't belong to this program")
    }

    return this.decode(info.data)
  }

  static async fetchMultiple(
    c: Connection,
    addresses: PublicKey[]
  ): Promise<Array<OrderbookInfo | null>> {
    const infos = await c.getMultipleAccountsInfo(addresses)

    return infos.map((info) => {
      if (info === null) {
        return null
      }
      if (!info.owner.equals(PROGRAM_ID)) {
        throw new Error("account doesn't belong to this program")
      }

      return this.decode(info.data)
    })
  }

  static decode(data: Buffer): OrderbookInfo {
    if (!data.slice(0, 8).equals(OrderbookInfo.discriminator)) {
      throw new Error("invalid account discriminator")
    }

    const dec = OrderbookInfo.layout.decode(data.slice(8))

    return new OrderbookInfo({
      admin: dec.admin,
      length: dec.length,
      applesMint: dec.applesMint,
      orangesMint: dec.orangesMint,
      bump: dec.bump,
      closed: dec.closed,
      id: dec.id,
      tradeLog: dec.tradeLog.map((item) => types.TradeRecord.fromDecoded(item)),
    })
  }

  toJSON(): OrderbookInfoJSON {
    return {
      admin: this.admin.toString(),
      length: this.length,
      applesMint: this.applesMint.toString(),
      orangesMint: this.orangesMint.toString(),
      bump: this.bump,
      closed: this.closed,
      id: this.id.toString(),
      tradeLog: this.tradeLog.map((item) => item.toJSON()),
    }
  }

  static fromJSON(obj: OrderbookInfoJSON): OrderbookInfo {
    return new OrderbookInfo({
      admin: new PublicKey(obj.admin),
      length: obj.length,
      applesMint: new PublicKey(obj.applesMint),
      orangesMint: new PublicKey(obj.orangesMint),
      bump: obj.bump,
      closed: obj.closed,
      id: new PublicKey(obj.id),
      tradeLog: obj.tradeLog.map((item) => types.TradeRecord.fromJSON(item)),
    })
  }
}

Line 116 contains error (pictured)
image
Not sure if the "real" error is that dec should be typed, or what.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.