Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/metaplex-foundation/solita
Genrates an SDK API from solana contract IDL.
https://github.com/metaplex-foundation/solita
blockchain js metaplex nft solana
Last synced: 2 months ago
JSON representation
Genrates an SDK API from solana contract IDL.
- Host: GitHub
- URL: https://github.com/metaplex-foundation/solita
- Owner: metaplex-foundation
- License: apache-2.0
- Created: 2021-12-14T19:33:48.000Z (almost 3 years ago)
- Default Branch: master
- Last Pushed: 2023-11-22T22:56:15.000Z (about 1 year ago)
- Last Synced: 2024-10-09T11:07:40.362Z (2 months ago)
- Topics: blockchain, js, metaplex, nft, solana
- Language: TypeScript
- Homepage:
- Size: 334 KB
- Stars: 140
- Watchers: 1
- Forks: 31
- Open Issues: 17
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
- awesome - metaplex-foundation/solita - Genrates an SDK API from solana contract IDL. (TypeScript)
- solana-awesome - Link
- awesome-solana - Solita - foundation/solita.svg?style=social) Generates an SDK API from solana contract IDL (written by Metaplex to generate typescript SDK from Shank IDL) (Code / Frameworks)
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)
**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)## 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): [, number] {
[..]
}export function serialize(instance: 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