{"id":13455332,"url":"https://github.com/metaplex-foundation/solita","last_synced_at":"2025-04-04T18:04:43.539Z","repository":{"id":37082929,"uuid":"438376857","full_name":"metaplex-foundation/solita","owner":"metaplex-foundation","description":"Genrates an SDK API from solana contract IDL.","archived":false,"fork":false,"pushed_at":"2023-11-22T22:56:15.000Z","size":342,"stargazers_count":160,"open_issues_count":21,"forks_count":37,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-28T17:11:33.716Z","etag":null,"topics":["blockchain","js","metaplex","nft","solana"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/metaplex-foundation.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2021-12-14T19:33:48.000Z","updated_at":"2025-03-26T02:22:55.000Z","dependencies_parsed_at":"2023-11-22T23:26:57.644Z","dependency_job_id":"cede7b97-26e7-414a-89f7-d22bd3696dbd","html_url":"https://github.com/metaplex-foundation/solita","commit_stats":{"total_commits":116,"total_committers":4,"mean_commits":29.0,"dds":"0.13793103448275867","last_synced_commit":"1b379fe47e272c3b6ab680bce2dfa6ae4708b199"},"previous_names":[],"tags_count":44,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/metaplex-foundation%2Fsolita","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/metaplex-foundation%2Fsolita/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/metaplex-foundation%2Fsolita/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/metaplex-foundation%2Fsolita/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/metaplex-foundation","download_url":"https://codeload.github.com/metaplex-foundation/solita/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247226213,"owners_count":20904465,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["blockchain","js","metaplex","nft","solana"],"created_at":"2024-07-31T08:01:04.018Z","updated_at":"2025-04-04T18:04:43.518Z","avatar_url":"https://github.com/metaplex-foundation.png","language":"TypeScript","funding_links":[],"categories":["Development Tools and Libraries","Code","TypeScript","Developer Resources"],"sub_categories":["Development Frameworks and SDKs","Frameworks","Dev Tooling"],"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)\n\n**Sol** ana **I** DL **t** o **A** PI generator.\n\n![solita-logo](./assets/solita-logo.gif)\n\n\u003c!-- START doctoc generated TOC please keep comment here to allow auto update --\u003e\n\u003c!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --\u003e\n**Table of Contents**  *generated with [DocToc](https://github.com/thlorenz/doctoc)*\n\n- [How does it Work?](#how-does-it-work)\n- [Shank + Solita Example (Recommended)](#shank--solita-example-recommended)\n  - [Full Example: Token Metadata Solita + Shank Setup](#full-example-token-metadata-solita--shank-setup)\n- [Anchor + Solita Example (Recommended)](#anchor--solita-example-recommended)\n  - [Full Example: MPL Candy Machine Solita + Anchor Setup](#full-example-mpl-candy-machine-solita--anchor-setup)\n- [Type Aliases](#type-aliases)\n- [Custom De/Serializers](#custom-deserializers)\n- [Hooking into IDL Creation](#hooking-into-idl-creation)\n- [Advanced Shank + Solita Example](#advanced-shank--solita-example)\n- [Advanced Anchor + Solita Example](#advanced-anchor--solita-example)\n- [Solita in the Wild](#solita-in-the-wild)\n- [LICENSE](#license)\n\n\u003c!-- END doctoc generated TOC please keep comment here to allow auto update --\u003e\n\n## How does it Work?\n\n_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\n[anchor](https://github.com/project-serum/anchor) or\n[shank](https://github.com/metaplex-foundation/shank).\n\n## Shank + Solita Example (Recommended)\n\nIn order to use _solita_ with shank do the following:\n\n- add the `shank` library to your Rust project via `cargo add shank`\n- annotate your Rust program as outlined [here](https://docs.rs/crate/shank_macro/latest)\n- add `solita` to the dev dependencies of your SDK package via `yarn add -D @metaplex-foundation/solita`\n- add a config similar to the below into `.solitarc.js` in your SDK package root\n\n```js\nconst path = require('path');\nconst programDir = path.join(__dirname, '..', 'program');\nconst idlDir = path.join(__dirname, 'idl');\nconst sdkDir = path.join(__dirname, 'src', 'generated');\nconst binaryInstallDir = path.join(__dirname, '.crates');\n\nmodule.exports = {\n  idlGenerator: 'shank',\n  programName: 'mpl_token_vault',\n  idlDir,\n  sdkDir,\n  binaryInstallDir,\n  programDir,\n};\n```\n\nNow running `yarn solita` from the same folder will take care of installing the matching\n_shank_ binary and generating the IDL and SDK.\n\nRun it each time you make a change to your program to generate the TypeScript SDK.\n\nSince we're writing the _shank_ binary to `.crates/` you should add that folder to your\n`.gitignore`.\n\n### Full Example: Token Metadata Solita + Shank Setup\n\n- [annotated instructions](https://github.com/metaplex-foundation/metaplex-program-library/blob/5f0c0656ff250f7a70643c06306962186f37ef5d/token-metadata/program/src/instruction.rs#L80)\n- [annotated accounts](https://github.com/metaplex-foundation/metaplex-program-library/blob/master/token-metadata/program/src/state.rs#L194)\n- [generated TypeScript](https://github.com/metaplex-foundation/metaplex-program-library/tree/master/token-metadata/js/src/generated)\n\n## Anchor + Solita Example (Recommended)\n\nIn order to use _solita_ with anchor do the following:\n\n- annotate your Rust program with anchor attributes \n- add `solita` to the dev dependencies of your SDK package via `yarn add -D @metaplex-foundation/solita`\n- add a config similar to the below into `.solitarc.js` in your SDK package root\n\n```js\nconst path = require('path');\nconst programDir = path.join(__dirname, '..', 'program');\nconst idlDir = path.join(__dirname, 'idl');\nconst sdkDir = path.join(__dirname, 'src', 'generated');\nconst binaryInstallDir = path.join(__dirname, '.crates');\n\nmodule.exports = {\n  idlGenerator: 'anchor',\n  programName: 'auction_house',\n  programId: 'hausS13jsjafwWwGqZTUQRmWyvyxn9EQpqMwV1PBBmk',\n  idlDir,\n  sdkDir,\n  binaryInstallDir,\n  programDir,\n};\n```\n\nNow running `yarn solita` from the same folder will take care of installing the matching\n_anchor_ binary and generating the IDL and SDK.\n\nRun it each time you make a change to your program to generate the TypeScript SDK.\n\nSince we're writing the _anchor_ binary to `.crates/` you should add that folder to your\n`.gitignore`.\n\n\n**NOTE**: that for _anchor_ generated IDL an optional `anchorRemainingAccounts` property is\nadded to each set of instruction accounts. If your programs are not using those you can\nspecifically turn that off by setting `anchorRemainingAccounts: false`.\n\n### Full Example: MPL Candy Machine Solita + Anchor Setup\n  \n- [annotated anchor program](https://github.com/metaplex-foundation/metaplex-program-library/blob/5f0c0656ff250f7a70643c06306962186f37ef5d/candy-machine/program/src/lib.rs) \n- [generated TypeScript](https://github.com/metaplex-foundation/metaplex-program-library/tree/master/candy-machine/js/src/generated)\n\n## Type Aliases\n\nIn order to have Solita resolve specific types to a Rust builtin type please provide a\ntype alias map as in the below config. Solita then will treat those as if they were the aliased\ntype.\n\n```js\nmodule.exports = {\n  idlGenerator: 'anchor',\n  [ .. ]\n  typeAliases: {\n    UnixTimestamp: 'i64'\n  }\n};\n```\n\n## Custom De/Serializers\n\nFor some accounts the generated de/serializers don't work. In those cases a custom\nde/serializer can be specified.\n\nThis is as simple as adding a module to your project which exports a either or both of the\nbelow functions:\n\n```ts\nexport function deserialize(buf: Buffer, offset = 0): [\u003cAccount\u003e, number] {\n  [..]\n}\n\nexport function serialize(instance: \u003cAccount\u003eArgs, byteSize?: number): [Buffer, number]\n  [..]\n}\n```\n\nThen provide them as `serializers` to `Solita` or via the solita config:\n\n```js\nmodule.exports = {\n  idlGenerator: 'shank',\n  [ .. ]\n  serializers: {\n    Metadata: './src/custom/metadata-deserializer.ts',\n  },\n};\n```\n\n## Hooking into IDL Creation\n\nIt is possible to modify the IDL generated by _anchor_ or _shank_ _before_ it is passed to the\n_solita_ code generator. \nJust provide an _idlHook_ of the type `(idl: Idl) =\u003e Idl` via the solita config.\n\nThis hook takes the current idl as an input and returns the modified version. It is ok to\nmodify the `idl` parameter in place if that is more convenient.\n\nPlease refer to the [definition of the `Idl`\ntype](https://github.com/metaplex-foundation/solita/blob/f329ceae1fb0686c1e5df8e5167e52c210b8700a/src/types.ts#L172-L182)\nfor more details.\n\n**Example:**\n\n```js\nmodule.exports = {\n  idlGenerator: 'anchor',\n  [ .. ]\n  idlHook: (idl) =\u003e {\n    return { ...idl, hola: 'mundo' }\n  }\n};\n```\n\n## Advanced Shank + Solita Example\n\nIf you need more control you can also add a script. However you're on your own to ensure that\nthe globally installed _shank_ binary matches the version of its library you're using.\n\n- globally install `shank` via `cargo install shank-cli`\n- add a script similar to the below to your SDK package and \n \n```js\nconst path = require('path');\nconst { Solita } = require('@metaplex-foundation/solita');\nconst {\n  rustbinMatch,\n  confirmAutoMessageConsole,\n} = require('@metaplex-foundation/rustbin')\nconst { spawn } = require('child_process');\n\nconst programDir = path.join(__dirname, '..', '..', 'program');\nconst cargoToml = path.join(programDir, 'Cargo.toml')\nconst generatedIdlDir = path.join(__dirname, '..', 'idl');\nconst generatedSDKDir = path.join(__dirname, '..', 'src', 'generated');\nconst rootDir = path.join(__dirname, '..', '.crates')\n\nconst PROGRAM_NAME = 'mpl_token_metadata';\nconst rustbinConfig = {\n  rootDir,\n  binaryName: 'shank',\n  binaryCrateName: 'shank-cli',\n  libName: 'shank',\n  dryRun: false,\n  cargoToml,\n}\n\nasync function main() {\n  const { fullPathToBinary: shankExecutable } = await rustbinMatch(\n    rustbinConfig,\n    confirmAutoMessageConsole\n  )\n  const shank = spawn(shankExecutable, ['idl', '--out-dir', generatedIdlDir, '--crate-root', programDir])\n    .on('error', (err) =\u003e {\n      console.error(err);\n      if (err.code === 'ENOENT') {\n        console.error(\n          'Ensure that `shank` is installed and in your path, see:\\n  https://github.com/metaplex-foundation/shank\\n',\n        );\n      }\n      process.exit(1);\n    })\n    .on('exit', () =\u003e {\n      generateTypeScriptSDK();\n    });\n\n  shank.stdout.on('data', (buf) =\u003e console.log(buf.toString('utf8')));\n  shank.stderr.on('data', (buf) =\u003e console.error(buf.toString('utf8')));\n}\n\nasync function generateTypeScriptSDK() {\n  console.error('Generating TypeScript SDK to %s', generatedSDKDir);\n  const generatedIdlPath = path.join(generatedIdlDir, `${PROGRAM_NAME}.json`);\n\n  const idl = require(generatedIdlPath);\n  const gen = new Solita(idl, { formatCode: true });\n  await gen.renderAndWriteTo(generatedSDKDir);\n\n  console.error('Success!');\n\n  process.exit(0);\n}\n\nmain().catch((err) =\u003e {\n  console.error(err)\n  process.exit(1)\n})\n```\n\n## Advanced Anchor + Solita Example\n\nIf you need more control you can also add a script. However you're on your own to ensure that\nthe globally installed _anchor_ binary matches the version of its library you're using.\n\n- globally [install anchor](https://book.anchor-lang.com/chapter_2/installation.html)\n- add a script similar to the below to your SDK package\n\n```js\nconst path = require('path');\nconst {\n  rustbinMatch,\n  confirmAutoMessageConsole,\n} = require('@metaplex-foundation/rustbin')\nconst { spawn } = require('child_process');\nconst { Solita } = require('@metaplex-foundation/solita');\nconst { writeFile } = require('fs/promises');\n\nconst PROGRAM_NAME = 'candy_machine';\nconst PROGRAM_ID = 'cndy3Z4yapfJBmL3ShUp5exZKqR3z33thTzeNMm2gRZ';\n\nconst programDir = path.join(__dirname, '..', '..', 'program');\nconst cargoToml = path.join(programDir, 'Cargo.toml')\nconst generatedIdlDir = path.join(__dirname, '..', 'idl');\nconst generatedSDKDir = path.join(__dirname, '..', 'src', 'generated');\nconst rootDir = path.join(__dirname, '..', '.crates')\n\nasync function main() {\n  const { fullPathToBinary: anchorExecutable } = await rustbinMatch(\n    rustbinConfig,\n    confirmAutoMessageConsole\n  )\n  const anchor = spawn(anchorExecutable, ['build', '--idl', generatedIdlDir], { cwd: programDir })\n    .on('error', (err) =\u003e {\n      console.error(err);\n      // @ts-ignore this err does have a code\n      if (err.code === 'ENOENT') {\n        console.error(\n          'Ensure that `anchor` is installed and in your path, see:\\n  https://project-serum.github.io/anchor/getting-started/installation.html#install-anchor\\n',\n        );\n      }\n      process.exit(1);\n    })\n    .on('exit', () =\u003e {\n      console.log('IDL written to: %s', path.join(generatedIdlDir, `${PROGRAM_NAME}.json`));\n      generateTypeScriptSDK();\n    });\n\n  anchor.stdout.on('data', (buf) =\u003e console.log(buf.toString('utf8')));\n  anchor.stderr.on('data', (buf) =\u003e console.error(buf.toString('utf8')));\n}\n\nasync function generateTypeScriptSDK() {\n  console.error('Generating TypeScript SDK to %s', generatedSDKDir);\n  const generatedIdlPath = path.join(generatedIdlDir, `${PROGRAM_NAME}.json`);\n\n  const idl = require(generatedIdlPath);\n  if (idl.metadata?.address == null) {\n    idl.metadata = { ...idl.metadata, address: PROGRAM_ID };\n    await writeFile(generatedIdlPath, JSON.stringify(idl, null, 2));\n  }\n  const gen = new Solita(idl, { formatCode: true });\n  await gen.renderAndWriteTo(generatedSDKDir);\n\n  console.error('Success!');\n\n  process.exit(0);\n}\n\nmain().catch((err) =\u003e {\n  console.error(err)\n  process.exit(1)\n})\n```\n\n## Solita in the Wild\n\nFind more _solita_, _shank_ and _anchor_  examples inside the [metaplex-program-library](https://github.com/metaplex-foundation/metaplex-program-library).\n\n## LICENSE\n\nApache-2.0\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmetaplex-foundation%2Fsolita","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmetaplex-foundation%2Fsolita","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmetaplex-foundation%2Fsolita/lists"}