Spaces:
Runtime error
Runtime error
sidebar_position: 9 | |
# How to Publish a Contract to NPM | |
## What is a Smart Contract Library? | |
A smart contract library can provide methods which can be reused in many contracts. Developers can use existing libraries to reduce the cost of developing their own contracts. | |
A smart contract library is different from a smart contract in these ways: | |
* A smart contract library can not have any public/entry `@method`s, which means a library can not be deployed or called directly through a tx. They can only be called within a smart contract or another library. | |
* A smart contract library can not have any stateful properties, i.e. `@prop(true)` properties. But a property declared as `@prop()` is fine. | |
## Write a Smart Contract Library | |
Using `sCrypt` we can create a smart contract library class like this: | |
```ts | |
class MyLib extends SmartContractLib { | |
@prop() | |
readonly buf: ByteString; | |
constructor(buf: ByteString) { | |
super(...arguments); | |
this.buf = buf; | |
} | |
@method() | |
append(content: ByteString) { | |
this.buf += content; | |
} | |
@method() | |
static add(x: bigint, y: bigint): bigint { | |
return x + y; | |
} | |
} | |
``` | |
A smart contract library can be declared as a class that extends `SmartContractLib`. It may also have `@prop`s and `@method`s like smart contracts which have the same rules [introduced before](./how-to-write-a-contract). A smart contract library can be used within `@method`s like this: | |
```ts | |
class MyContract extends SmartContract { | |
@method() | |
public unlock(x: ByteString) { | |
let myLib = new MyLib(hexToByteString('0123')); | |
myLib.append(x); | |
assert(MyLib.add(1n, 2n) === 3n, 'incorrect sum'); | |
} | |
} | |
``` | |
## Test a Smart Contract Library | |
You can test your smart contract library as a normal class, for example, writing some unit tests: | |
```ts | |
describe('Test SmartContractLib `MyLib`', () => { | |
it('should pass unit test successfully.', () => { | |
expect(MyLib.add(1n, 2n)).to.eq(3n) | |
}) | |
}) | |
``` | |
Also you can write a smart contract using the library, then have some tests for the contract, like: | |
```ts | |
class TestLib extends SmartContract { | |
@method | |
public unlock(x: bigint) { | |
assert(MyLib.add(1n, 2n) == x, 'incorrect sum') | |
} | |
} | |
describe('Test SmartContractLib `Lib`', () => { | |
before(async() => { | |
await TestLib.compile() | |
}) | |
it('should pass integration test successfully.', () => { | |
let testLib = new TestLib() | |
let result = testLib.verify(self => self.unlock(3n)) | |
expect(result.success, result.error).to.be.true | |
} | |
}) | |
``` | |
## Create and Publish a Library Project Using sCrypt CLI | |
The following command will create a demo scryptTS library along with tests and scaffolding: | |
```sh | |
scrypt project --lib <your-lib-name> | |
``` | |
Note the `lib` option is turned on. | |
You can publish the library on [NPM](https://www.npmjs.com/) by running the following command in the project's root directory: | |
```sh | |
npm publish | |
``` | |
This will build the project and publish it on NPM. After the library is published, users can simply import it in any other project just like regular NPM packages. | |
:::note | |
Named imports are not supported yet. You should only import like the following. | |
::: | |
```ts | |
import { MyLib } from “my_package” | |
``` | |
### Advanced | |
For the import system working properly, you should always publish the auto-generated sCrypt contracts (including `scrypt.index.json` file) along with the javascript outputs. The structure of the package could be like this: | |
``` | |
node_modules | |
|__ my_package | |
|__ dist | |
|__ myLib.js | |
|__ myLib.d.ts | |
|__ artifacts | |
|__ myLib.scrypt | |
|__ scrypt.index.json | |
… | |
``` | |
The `scrypt.index.json` file will be generated at TypeScript compile time in the same directory of your `tsconfig.json` which should be placed in the root folder. It shall not be moved or modified manually. The folder for auto-generated `.scrypt` files (`artifacts` in the upper file tree) can be changed by configuring the `outDir` option in `tsconfig.json`, like: | |
```json | |
"compilerOptions": { | |
"plugins": [ | |
{ | |
"transform": "scrypt-ts/dist/transformation/transformer", | |
"transformProgram": "true", | |
"outDir": "my_scrypts_dir" | |
} | |
] | |
} | |
``` | |
You should always publish the auto-generated sCrypt files along with the package. If you are familiar with sCrypt development and want to apply some improvements to the auto-generated files, for example using an inline asm function to replace an ordinary function to reduce the final script size, you could just modify the auto-generated file as you wish before publishing it. Take a look at how [scrytp-ts-lib](https://github.com/sCrypt-Inc/scrypt-ts-lib/tree/master/optimizations) does it. | |
:::note | |
You should modify the auto-generated files with caution and make sure that the modification passes the tests. | |
::: | |
## Related Tools | |
### `scrypt-ts-lib` | |
It’s a collection of smart contract libraries provided by us. You can find some useful tools [here](https://github.com/sCrypt-Inc/scrypt-ts-lib). Also you are welcome to contribute. | |