# @metaplex-foundation/solita

> Generates SDK API from solana contract IDL.

Latest version **0.20.1** (published 2023-11-22) · Apache-2.0 license · 0 weekly downloads

## Install

```sh
npm install @metaplex-foundation/solita
pnpm add @metaplex-foundation/solita
yarn add @metaplex-foundation/solita
bun add @metaplex-foundation/solita
```

Provides the command `solita`.

## Health

**Score 40/100 (D)** — status: abandoned.

Positive: has types; no vulnerabilities; high maintenance score; high quality score.

Warnings: low downloads; no esm support; pre 1.0.

Negative: abandoned.

## Facts

| | |
|---|---|
| Version | 0.20.1 |
| Published | 2023-11-22 |
| First published | 2022-01-22 |
| Weekly downloads | 0 |
| License | Apache-2.0 |
| TypeScript types | bundled |
| Module format | CommonJS |
| Dependencies | 11 |
| Unpacked size | 258.3 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| GitHub stars | 176 |
| Author | Thorsten Lorenz |
| Maintainers | danenbm, nhanphan, blockiosaurus, 0x_febo, svc01-metaplex, brandontulsi |
| Keywords | solana, blockchain, IDL, API |

## Links

- npm: https://www.npmjs.com/package/@metaplex-foundation/solita
- Repository: https://github.com/metaplex-foundation/solita
- Homepage: https://github.com/metaplex-foundation/solita#readme
- Issues: https://github.com/metaplex-foundation/solita/issues
- npm.io page: https://npm.io/package/@metaplex-foundation/solita

## Dependencies (11)

- [spok](https://npm.io/package/spok.md) ^1.4.3
- [debug](https://npm.io/package/debug.md) ^4.3.3
- [prettier](https://npm.io/package/prettier.md) ^2.5.1
- [camelcase](https://npm.io/package/camelcase.md) ^6.2.1
- [js-sha256](https://npm.io/package/js-sha256.md) ^0.9.0
- [snake-case](https://npm.io/package/snake-case.md) ^3.0.4
- [ansi-colors](https://npm.io/package/ansi-colors.md) ^4.1.3
- [@solana/web3.js](https://npm.io/package/@solana/web3.js.md) ^1.56.2
- [@metaplex-foundation/beet](https://npm.io/package/@metaplex-foundation/beet.md) ^0.7.1
- [@metaplex-foundation/rustbin](https://npm.io/package/@metaplex-foundation/rustbin.md) ^0.3.0
- [@metaplex-foundation/beet-solana](https://npm.io/package/@metaplex-foundation/beet-solana.md) ^0.3.1

## Alternatives

- [@sindresorhus/slugify](https://npm.io/package/@sindresorhus/slugify.md) — 3.7M weekly downloads
- [solid-js](https://npm.io/package/solid-js.md) — 2.7M weekly downloads
- [expo-glass-effect](https://npm.io/package/expo-glass-effect.md) — 2.5M weekly downloads
- [nanoassert](https://npm.io/package/nanoassert.md) — 780.8K weekly downloads
- [@ffmpeg/ffmpeg](https://npm.io/package/@ffmpeg/ffmpeg.md) — 529.5K weekly downloads

## Recent versions

- 0.20.1 (latest) — 2023-11-22
- 0.20.0 — 2023-07-06
- 0.19.4 — 2023-02-17
- 0.19.3 — 2022-12-16
- 0.19.2 — 2022-12-15
- 0.19.1 — 2022-11-23
- 0.19.0 — 2022-10-18
- 0.18.0 — 2022-09-24
- 0.17.1 — 2022-09-23
- 0.17.0 — 2022-09-22
- 0.16.0 — 2022-09-20
- 0.15.2 — 2022-09-01
- 0.15.1 — 2022-08-27
- 0.15.0 — 2022-08-26
- 0.14.0 — 2022-08-23
- … 29 more at https://npm.io/package/@metaplex-foundation/solita/versions

## README

# solita [![Build Lint and Test Solita](https://github.com/metaplex-foundation/solita/actions/workflows/solita.yml/badge.svg)](https://github.com/metaplex-foundation/solita/actions/workflows/solita.yml)

**Sol** ana **I** DL **t** o **A** PI generator.

![solita-logo](./assets/solita-logo.gif)

<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
**Table of Contents**  *generated with [DocToc](https://github.com/thlorenz/doctoc)*

- [How does it Work?](#how-does-it-work)
- [Shank + Solita Example (Recommended)](#shank--solita-example-recommended)
  - [Full Example: Token Metadata Solita + Shank Setup](#full-example-token-metadata-solita--shank-setup)
- [Anchor + Solita Example (Recommended)](#anchor--solita-example-recommended)
  - [Full Example: MPL Candy Machine Solita + Anchor Setup](#full-example-mpl-candy-machine-solita--anchor-setup)
- [Type Aliases](#type-aliases)
- [Custom De/Serializers](#custom-deserializers)
- [Hooking into IDL Creation](#hooking-into-idl-creation)
- [Advanced Shank + Solita Example](#advanced-shank--solita-example)
- [Advanced Anchor + Solita Example](#advanced-anchor--solita-example)
- [Solita in the Wild](#solita-in-the-wild)
- [LICENSE](#license)

<!-- END doctoc generated TOC please keep comment here to allow auto update -->

## How does it Work?

_Solita_ generates a low level TypeScript SDK for your _Solana_ Rust programs from the [IDL](https://en.wikipedia.org/wiki/Interface_description_language) extracted by
[anchor](https://github.com/project-serum/anchor) or
[shank](https://github.com/metaplex-foundation/shank).

## Shank + Solita Example (Recommended)

In order to use _solita_ with shank do the following:

- add the `shank` library to your Rust project via `cargo add shank`
- annotate your Rust program as outlined [here](https://docs.rs/crate/shank_macro/latest)
- add `solita` to the dev dependencies of your SDK package via `yarn add -D @metaplex-foundation/solita`
- add a config similar to the below into `.solitarc.js` in your SDK package root

```js
const path = require('path');
const programDir = path.join(__dirname, '..', 'program');
const idlDir = path.join(__dirname, 'idl');
const sdkDir = path.join(__dirname, 'src', 'generated');
const binaryInstallDir = path.join(__dirname, '.crates');

module.exports = {
  idlGenerator: 'shank',
  programName: 'mpl_token_vault',
  idlDir,
  sdkDir,
  binaryInstallDir,
  programDir,
};
```

Now running `yarn solita` from the same folder will take care of installing the matching
_shank_ binary and generating the IDL and SDK.

Run it each time you make a change to your program to generate the TypeScript SDK.

Since we're writing the _shank_ binary to `.crates/` you should add that folder to your
`.gitignore`.

### Full Example: Token Metadata Solita + Shank Setup

- [annotated instructions](https://github.com/metaplex-foundation/metaplex-program-library/blob/5f0c0656ff250f7a70643c06306962186f37ef5d/token-metadata/program/src/instruction.rs#L80)
- [annotated accounts](https://github.com/metaplex-foundation/metaplex-program-library/blob/master/token-metadata/program/src/state.rs#L194)
- [generated TypeScript](https://github.com/metaplex-foundation/metaplex-program-library/tree/master/token-metadata/js/src/generated)

## Anchor + Solita Example (Recommended)

In order to use _solita_ with anchor do the following:

- annotate your Rust program with anchor attributes 
- add `solita` to the dev dependencies of your SDK package via `yarn add -D @metaplex-foundation/solita`
- add a config similar to the below into `.solitarc.js` in your SDK package root

```js
const path = require('path');
const programDir = path.join(__dirname, '..', 'program');
const idlDir = path.join(__dirname, 'idl');
const sdkDir = path.join(__dirname, 'src', 'generated');
const binaryInstallDir = path.join(__dirname, '.crates');

module.exports = {
  idlGenerator: 'anchor',
  programName: 'auction_house',
  programId: 'hausS13jsjafwWwGqZTUQRmWyvyxn9EQpqMwV1PBBmk',
  idlDir,
  sdkDir,
  binaryInstallDir,
  programDir,
};
```

Now running `yarn solita` from the same folder will take care of installing the matching
_anchor_ binary and generating the IDL and SDK.

Run it each time you make a change to your program to generate the TypeScript SDK.

Since we're writing the _anchor_ binary to `.crates/` you should add that folder to your
`.gitignore`.


**NOTE**: that for _anchor_ generated IDL an optional `anchorRemainingAccounts` property is
added to each set of instruction accounts. If your programs are not using those you can
specifically turn that off by setting `anchorRemainingAccounts: false`.

### Full Example: MPL Candy Machine Solita + Anchor Setup
  
- [annotated anchor program](https://github.com/metaplex-foundation/metaplex-program-library/blob/5f0c0656ff250f7a70643c06306962186f37ef5d/candy-machine/program/src/lib.rs) 
- [generated TypeScript](https://github.com/metaplex-foundation/metaplex-program-library/tree/master/candy-machine/js/src/generated)

## Type Aliases

In order to have Solita resolve specific types to a Rust builtin type please provide a
type alias map as in the below config. Solita then will treat those as if they were the aliased
type.

```js
module.exports = {
  idlGenerator: 'anchor',
  [ .. ]
  typeAliases: {
    UnixTimestamp: 'i64'
  }
};
```

## Custom De/Serializers

For some accounts the generated de/serializers don't work. In those cases a custom
de/serializer can be specified.

This is as simple as adding a module to your project which exports a either or both of the
below functions:

```ts
export function deserialize(buf: Buffer, offset = 0): [<Account>, number] {
  [..]
}

export function serialize(instance: <Account>Args, byteSize?: number): [Buffer, number]
  [..]
}
```

Then provide them as `serializers` to `Solita` or via the solita config:

```js
module.exports = {
  idlGenerator: 'shank',
  [ .. ]
  serializers: {
    Metadata: './src/custom/metadata-deserializer.ts',
  },
};
```

## Hooking into IDL Creation

It is possible to modify the IDL generated by _anchor_ or _shank_ _before_ it is passed to the
_solita_ code generator. 
Just provide an _idlHook_ of the type `(idl: Idl) => Idl` via the solita config.

This hook takes the current idl as an input and returns the modified version. It is ok to
modify the `idl` parameter in place if that is more convenient.

Please refer to the [definition of the `Idl`
type](https://github.com/metaplex-foundation/solita/blob/f329ceae1fb0686c1e5df8e5167e52c210b8700a/src/types.ts#L172-L182)
for more details.

**Example:**

```js
module.exports = {
  idlGenerator: 'anchor',
  [ .. ]
  idlHook: (idl) => {
    return { ...idl, hola: 'mundo' }
  }
};
```

## Advanced Shank + Solita Example

If you need more control you can also add a script. However you're on your own to ensure that
the globally installed _shank_ binary matches the version of its library you're using.

- globally install `shank` via `cargo install shank-cli`
- add a script similar to the below to your SDK package and 
 
```js
const path = require('path');
const { Solita } = require('@metaplex-foundation/solita');
const {
  rustbinMatch,
  confirmAutoMessageConsole,
} = require('@metaplex-foundation/rustbin')
const { spawn } = require('child_process');

const programDir = path.join(__dirname, '..', '..', 'program');
const cargoToml = path.join(programDir, 'Cargo.toml')
const generatedIdlDir = path.join(__dirname, '..', 'idl');
const generatedSDKDir = path.join(__dirname, '..', 'src', 'generated');
const rootDir = path.join(__dirname, '..', '.crates')

const PROGRAM_NAME = 'mpl_token_metadata';
const rustbinConfig = {
  rootDir,
  binaryName: 'shank',
  binaryCrateName: 'shank-cli',
  libName: 'shank',
  dryRun: false,
  cargoToml,
}

async function main() {
  const { fullPathToBinary: shankExecutable } = await rustbinMatch(
    rustbinConfig,
    confirmAutoMessageConsole
  )
  const shank = spawn(shankExecutable, ['idl', '--out-dir', generatedIdlDir, '--crate-root', programDir])
    .on('error', (err) => {
      console.error(err);
      if (err.code === 'ENOENT') {
        console.error(
          'Ensure that `shank` is installed and in your path, see:\n  https://github.com/metaplex-foundation/shank\n',
        );
      }
      process.exit(1);
    })
    .on('exit', () => {
      generateTypeScriptSDK();
    });

  shank.stdout.on('data', (buf) => console.log(buf.toString('utf8')));
  shank.stderr.on('data', (buf) => console.error(buf.toString('utf8')));
}

async function generateTypeScriptSDK() {
  console.error('Generating TypeScript SDK to %s', generatedSDKDir);
  const generatedIdlPath = path.join(generatedIdlDir, `${PROGRAM_NAME}.json`);

  const idl = require(generatedIdlPath);
  const gen = new Solita(idl, { formatCode: true });
  await gen.renderAndWriteTo(generatedSDKDir);

  console.error('Success!');

  process.exit(0);
}

main().catch((err) => {
  console.error(err)
  process.exit(1)
})
```

## Advanced Anchor + Solita Example

If you need more control you can also add a script. However you're on your own to ensure that
the globally installed _anchor_ binary matches the version of its library you're using.

- globally [install anchor](https://book.anchor-lang.com/chapter_2/installation.html)
- add a script similar to the below to your SDK package

```js
const path = require('path');
const {
  rustbinMatch,
  confirmAutoMessageConsole,
} = require('@metaplex-foundation/rustbin')
const { spawn } = require('child_process');
const { Solita } = require('@metaplex-foundation/solita');
const { writeFile } = require('fs/promises');

const PROGRAM_NAME = 'candy_machine';
const PROGRAM_ID = 'cndy3Z4yapfJBmL3ShUp5exZKqR3z33thTzeNMm2gRZ';

const programDir = path.join(__dirname, '..', '..', 'program');
const cargoToml = path.join(programDir, 'Cargo.toml')
const generatedIdlDir = path.join(__dirname, '..', 'idl');
const generatedSDKDir = path.join(__dirname, '..', 'src', 'generated');
const rootDir = path.join(__dirname, '..', '.crates')

async function main() {
  const { fullPathToBinary: anchorExecutable } = await rustbinMatch(
    rustbinConfig,
    confirmAutoMessageConsole
  )
  const anchor = spawn(anchorExecutable, ['build', '--idl', generatedIdlDir], { cwd: programDir })
    .on('error', (err) => {
      console.error(err);
      // @ts-ignore this err does have a code
      if (err.code === 'ENOENT') {
        console.error(
          'Ensure that `anchor` is installed and in your path, see:\n  https://project-serum.github.io/anchor/getting-started/installation.html#install-anchor\n',
        );
      }
      process.exit(1);
    })
    .on('exit', () => {
      console.log('IDL written to: %s', path.join(generatedIdlDir, `${PROGRAM_NAME}.json`));
      generateTypeScriptSDK();
    });

  anchor.stdout.on('data', (buf) => console.log(buf.toString('utf8')));
  anchor.stderr.on('data', (buf) => console.error(buf.toString('utf8')));
}

async function generateTypeScriptSDK() {
  console.error('Generating TypeScript SDK to %s', generatedSDKDir);
  const generatedIdlPath = path.join(generatedIdlDir, `${PROGRAM_NAME}.json`);

  const idl = require(generatedIdlPath);
  if (idl.metadata?.address == null) {
    idl.metadata = { ...idl.metadata, address: PROGRAM_ID };
    await writeFile(generatedIdlPath, JSON.stringify(idl, null, 2));
  }
  const gen = new Solita(idl, { formatCode: true });
  await gen.renderAndWriteTo(generatedSDKDir);

  console.error('Success!');

  process.exit(0);
}

main().catch((err) => {
  console.error(err)
  process.exit(1)
})
```

## Solita in the Wild

Find more _solita_, _shank_ and _anchor_  examples inside the [metaplex-program-library](https://github.com/metaplex-foundation/metaplex-program-library).

## LICENSE

Apache-2.0

---
_Source: https://npm.io/package/@metaplex-foundation/solita · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
