diff --git a/docs/.vuepress/configs/sidebar.ts b/docs/.vuepress/configs/sidebar.ts index 6b70f37..942d1fd 100644 --- a/docs/.vuepress/configs/sidebar.ts +++ b/docs/.vuepress/configs/sidebar.ts @@ -64,17 +64,7 @@ export const sidebar: Record = { text: 'SDK', children: [ '/build/sdk', - '/build/sdk/examplesSubstrateREST.md', - '/build/sdk/examplesSDK.md', - '/build/sdk/examplesLifeNFT.md', - '/build/sdk/examplesNesting.md', - // '/build/sdk/installation.md', -> moved to other pages - '/build/sdk/architecture.md', - '/build/sdk/methods.md', - '/build/sdk/ios.md', - '/build/sdk/android.md', - '/build/sdk/C_sharp.md', - // '/build/sdk/tools.md', -> this info exists in Tutorials section + '/build/sdk/examples-nesting.md', ] }, { @@ -170,6 +160,13 @@ export const sidebar: Record = { text: 'Blockchains', children: [ '/reference', + '/reference/sdk-endpoints.md' + ] + }, + { + text: "SDK", + children: [ + '/reference/sdk-methods.md' ] }, { diff --git a/docs/build/sdk/examples-nesting.md b/docs/build/sdk/examples-nesting.md new file mode 100644 index 0000000..5cbaf4b --- /dev/null +++ b/docs/build/sdk/examples-nesting.md @@ -0,0 +1,82 @@ +# Nesting + +The **nesting** feature allows you to create **nested tokens**. Thus, the topmost token will have a wallet address as its owner, while the owner of tokens nested in it will be the token above it. +The entire chain of nested tokens will be called a **bundle**. If you transfer a top-level token to another owner, all tokens in the bundle will go with it. + +> If you don't know how to create collections and tokens, start from [the beginning](./index.md) + +## Nesting permission + +Nesting is not allowed by default. You need to set special permissions at the collection level during creation. + + + +```typescript +const creationResult = await sdk.collection.create.submitWaitResult({ + name: "Test collection", + description: "My test collection", + tokenPrefix: "TST", + // Token owners and collection admins are allowed to nest tokens: + permissions: { + nesting: { + tokenOwner: true, + collectionAdmin: true, + // You can set collection ids allowed for nesting: + // restricted: [1] + }, + }, +}); +``` + +## Creating bundles + +```typescript +async function main() { + // ... Create collection and NFTs + // and get their IDs (collectionId, firstTokenId, secondTokenId) + + + await sdk.token.nest({ + parent: { collectionId, tokenId: firstTokenId }, + nested: { collectionId, tokenId: secondTokenId }, + }); +} + +main(); +``` + +## Check if the token is bundle + +- To check if the token is part of a bundle, use `isBundle` +- To get the hole bundle tree, use `getBundle` + +```typescript + const { isBundle } = await sdk.token.isBundle({ + collectionId, + tokenId: token1Id, + }); + + console.log('token 1 isBundle?', isBundle); + + const getBundleResult = await sdk.token.getBundle({ + collectionId, + tokenId: token1Id, + }); + + console.log('getBundleResult:', getBundleResult); +``` + + +## Unnest + +The reverse process is called unnesting, when a token no longer belongs to any token and its owner becomes the wallet address. + +```typescript +const { parsed, error } = await sdk.token.unnest.submitWaitResult({ + nested: { collectionId, tokenId: token2Id }, +}); +``` + +After unnesting the token with tokenId=2 is no longer part of the bundle. Neither is the token with tokenId=1 - because it no longer has any attached tokens. + +Read more about nesting functions in the [reference](../../reference/sdk-methods.md) diff --git a/docs/build/sdk/examplesNesting.md b/docs/build/sdk/examplesNesting.md deleted file mode 100644 index 2b93b10..0000000 --- a/docs/build/sdk/examplesNesting.md +++ /dev/null @@ -1,206 +0,0 @@ -# Nesting - -The **nesting** feature allows you to create **nested tokens**. Thus, the topmost token will have a wallet address as its owner, while the owner of tokens nested in it will be the token above it. -The entire chain of nested tokens will be called a **bundle**. If you transfer a top-level token to another owner, all tokens in the bundle will go with it. - - -## Creating a collection - -:warning: You need to set the permission field correctly in the collection. Otherwise, if the collection is not allowed to be nested, you won't be able to create a bundle of nested tokens in it. - -```typescript -export async function createCollection(sdk, address) { - const { parsed, error } = await sdk.collections.creation.submitWaitResult({ - address, - name: 'Test collection', - description: 'My test collection', - tokenPrefix: 'TST', - permissions: { - nesting: { - tokenOwner: true, - collectionAdmin: true, - }, - }, - }); - - if (error) { - console.log('create collection error', error); - process.exit(); - } - - const { collectionId } = parsed; - - return sdk.collections.get({ collectionId }); -} -``` - -## Token creation - -```typescript -export async function createToken(sdk, address, collectionId) { - const { parsed, error } = await sdk.tokens.create.submitWaitResult({ - address, - collectionId, - }); - - if (error) { - console.log('create token error', error); - process.exit(); - } - - const { tokenId } = parsed; - - return sdk.tokens.get({ collectionId, tokenId }); -} -``` - -## Creating a nested token - -```typescript -export async function createNestedToken(sdk, nestedArgs) { - const { address, parent, nested } = nestedArgs; - const { parsed, error } = await sdk.tokens.nest.submitWaitResult({ - address, - parent, - nested, - }); - - if (error) { - console.log('create token error', error); - process.exit(); - } - - const { collectionId, tokenId } = parsed; - - console.log(`Token ${tokenId} from collection ${collectionId} successfully nested`); - - return sdk.tokens.get({ collectionId, tokenId }); -} -``` - -## Example execute function - -Now let's wrap all our steps in an asynchronous function and run it, watching the result in the console - -```typescript -async function main() { - - // get signer - const signer = await KeyringProvider.fromMnemonic(mnemonic); - const address = signer.instance.address; - - // initialize sdk - const sdk = createSdk(signer); - - // create a collection - const collection = await createCollection(sdk, address); - console.log('collection', collection); - - // token creating - const token = await createToken(sdk, address, collection.id); - console.log('token', token); - const token2 = await createToken(sdk, address, collection.id); - console.log('token2', token2); - - // nesting (put tokenId 2 in tokenId 1) - const nestedToken = await createNestedToken(sdk, { - address, - parent: { - collectionId: collection.id, - tokenId: token.tokenId, - }, - nested: { - collectionId: collection.id, - tokenId: token2.tokenId, - }, - }); - - console.log('nestedToken', nestedToken); -} - -main(); -``` - -## IsBundle and getBundle - -Let's look at some more functions provided by our library: IsBundle and getBundle. Add the following code inside the `main` function - -```typescript - const isBundle = await sdk.tokens.isBundle({ - collectionId: collection.id, - tokenId: 1, - }); - - const isBundle2 = await sdk.tokens.isBundle({ - collectionId: collection.id, - tokenId: 2, - }); - - console.log('token 1 isBundle?', isBundle); - console.log('token 2 isBundle?', isBundle2); - - const result: any = await sdk.tokens.getBundle({ - collectionId: collection.id, - tokenId: 2, - }); - - console.log('getBundle', result); -``` -Running the whole process, you will see that both the top-level and the nested token are part of the bundle. - -## Unnest - -The reverse process is called `unnest`, when a token no longer belongs to any token and its owner becomes the wallet address. - -Add to your js file unnesting function - -```typescript -export async function createUnNestedToken(sdk: any, nestedArgs: any) { - const { address, parent, nested } = nestedArgs; - const { parsed, error } = await sdk.tokens.unnest.submitWaitResult({ - address, - parent, - nested, - }); - - if (error) { - console.log('create token error', error); - process.exit(); - } - - const { collectionId, tokenId } = parsed; - - console.log(`Token ${tokenId} from collection ${collectionId} successfully unnested`); - - return sdk.tokens.get({ collectionId, tokenId }); -} -``` - -and add its call to our function`main` - -```typescript -const unNestedToken = await createUnNestedToken(sdk, { - address, - parent: { - collectionId: collection.id, - tokenId: token.tokenId, - }, - nested: { - collectionId: collection.id, - tokenId: token2.tokenId, - }, - }); - - console.log('unNestedToken', unNestedToken); - - const isBundleAfterUnnest = await sdk.tokens.isBundle({ - collectionId: collection.id, - tokenId: 2, - }); - - console.log('token 2 isBundle?', isBundleAfterUnnest); - ``` -after unnesting you will see that the token with tokenId=2 is no longer part of the bundle. Neither is the token with tokenId=1 - because it no longer has any attached tokens. - - -Read more about this and other nesting functions [**here**](../sdk/methods.md) diff --git a/docs/build/sdk/examplesSDK.md b/docs/build/sdk/examplesSDK.md deleted file mode 100644 index 7678d64..0000000 --- a/docs/build/sdk/examplesSDK.md +++ /dev/null @@ -1,367 +0,0 @@ -# SDK usage examples - -On this page, we will provide examples of basic token handling methods: creating an account, creating a collection, creating and transferring a token. You can read more about other methods in the [methods section](../networks/methods.md). - -[[toc]] - -## Prerequisites - -All transactions require some fee, so in test purpose you can use Opal tokens, which you can get for free on your balance. These can be obtained via the [Telegram faucet bot](https://t.me/unique2faucet_opal_bot). - -## How to create an account - -In this tutorial, we will go through the entire process of creating an account using the Unique Network SDK. - -Consider using how you can create or get an account using the [Accounts](https://www.npmjs.com/package/@unique-nft/accounts) package. - -You will need to come up with or generate a mnemonic phrase (this is a set of words that can be used to create and restore your wallet). - -:warning: Never share your mnemonic phrase with anyone. If someone gets access to your mnemonic phrase, they can steal your funds. - -#### Generate a new account - -An easy way to create a new account is to use the `generateAccount` function from the `Accounts` package: - -```typescript:no-line-numbers -import { generateAccount, SignatureType } from "@unique-nft/accounts"; - -const account = await generateAccount({ - pairType: SignatureType.Sr25519, - meta: { - name: 'my_test_account' - } -}) - -console.log(account); - -``` - -
- -
- -#### Get an account from mnemonic phrase - -If you already have a mnemonic phrase, you can use it to get an account. Here is how the phrase looks like: - -`` -affair spoon other impact target solve extra range cute myself float panda -`` - -Here is how we can use it to get an account. - -```typescript:no-line-numbers -import { getAccountFromMnemonic } from '@unique-nft/accounts'; - -const account = await getAccountFromMnemonic({ - mnemonic: 'affair spoon other impact target solve extra range cute myself float panda', -}); -console.log(account); -``` - -
- -
- -Or, we can generate a mnemonic phrase and then get an account using it: - -```typescript:no-line-numbers -import { getAccountFromMnemonic } from '@unique-nft/accounts'; -import { mnemonicGenerate } from '@polkadot/util-crypto'; - -const mnemonicPhrase = mnemonicGenerate(); -const account = await getAccountFromMnemonic({ - mnemonic: mnemonicPhrase, -}); -``` - -#### Providers - -If you need to get an account from one specific provider, then it is not necessary to create an Accounts object, you can contact the provider directly: - -```typescript:no-line-numbers -import { Account } from '@unique-nft/accounts'; -import { KeyringProvider } from '@unique-nft/accounts/keyring'; -import { KeyringOptions } from '@polkadot/keyring/types'; - -const options: KeyringOptions = { - type: 'sr25519', -}; -const provider = new KeyringProvider(options); -await provider.init(); -const signer = provider.addSeed(''); -``` - -The following providers are supported: - - - - -```typescript:no-line-numbers -// The provider works directly with the chain using `KeyringPair` from the `@polkadotkeyring` package. -import { Account } from '@unique-nft/accounts'; -import { KeyringProvider } from '@unique-nft/accounts/keyring'; -import { KeyringOptions } from '@polkadot/keyring/types'; - -const options: KeyringOptions = { - type: 'sr25519', - }; - const provider = new KeyringProvider(options); - await provider.init(); - -const signer1 = provider.addSeed(''); -const signer2 = provider.addKeyfile(''); -``` - - - -```typescript:no-line-numbers -import { Account } from '@unique-nft/accounts'; -import { KeyringPair } from '@polkadot/keyring/types'; -import { - KeyringLocalOptions, - KeyringLocalProvider, - } from '@unique-nft/accounts/keyring-local'; - -const options: KeyringLocalOptions = { - type: 'sr25519', - passwordCallback: async (keyring: KeyringPair) => { - return ''; - }, - }; - const provider = new KeyringLocalProvider(options); - await provider.init(); - -const signer = provider.addUri('', ''); -``` - - - - -```typescript:no-line-numbers -// The provider uses the Polkadot extension (https://polkadot.js.org/extension) for the browser. -import { Web3AccountsOptions } from '@polkadot/extension-inject/types'; -import { Account } from '@unique-nft/accounts'; -import { PolkadotProvider } from '@unique-nft/accounts/polkadot'; - -const options: Web3AccountsOptions = { - accountType: ['sr25519'], - }; - const provider = new PolkadotProvider(options); - await provider.init(); - -const signer = await provider.first(); -``` - - - - -```typescript:no-line-numbers -// The provider uses the Metamask extension (https://metamask.io/download) for the browser. -import { Account } from '@unique-nft/accounts'; -import { MetamaskProvider } from '@unique-nft/accounts/metamask'; - -const provider = new MetamaskProvider(); -await provider.init(); - -const signer = await provider.first(); -``` - - - - -## How to create a new collection - - - - -```ts:no-line-numbers -import Sdk from '@unique-nft/sdk'; -import { KeyringProvider } from '@unique-nft/accounts/keyring'; - -const baseUrl = 'https://rest.unique.network/opal/v1'; -const mnemonic = 'bus ahead nation nice damp recall place dance guide media clap language'; - -// Creating an SDK client -function createSdk(account) { - const options = { - baseUrl, - signer: account, - } - return new Sdk(options); -} - -// Creating a sample collection -// The signer specified in the SDK constructor is used to sign an extrinsic -export async function createCollection(sdk, address) { - const { parsed, error } = await sdk.collections.creation.submitWaitResult({ - address, - name: 'Test collection', - description: 'My test collection', - tokenPrefix: 'TST', - }); - - if (error) { - console.log('Error occurred while creating a collection. ', error); - process.exit(); - } - - const { collectionId } = parsed; - - return sdk.collections.get({ collectionId }); -} - -// Entrypoint -async function main() { - const signer = await KeyringProvider.fromMnemonic(mnemonic); - const address = signer.instance.address; - - const sdk = createSdk(signer); - - const collection = await createCollection(sdk, address); - console.log('Collection was create. ID: ', collection); -} - -main(); -``` - - - - -## How to create a new token - - - - -```typescript -import { CreateTokenNewArguments } from '@unique-nft/substrate-client/tokens/types'; - -import { - UniqueCollectionSchemaToCreate, - COLLECTION_SCHEMA_NAME, - AttributeType, -} from '@unique-nft/substrate-client/tokens'; - -const createTokenArgs: CreateTokenNewArguments = { - address: '', - collectionId: 123, - data: { - encodedAttributes: { - '0': 0, - '1': [0], - '2': 'foo_bar', - }, - image: { - ipfsCid: '', - }, - }, -}; - -const result = await sdk.tokens.create.submitWaitResult(createArgs); -const { collectionId, tokenId } = result.parsed; - -const token = await sdk.tokens.get({ collectionId, tokenId }); -``` - - - -## How to transfer a token - - - - -```typescript -import { TransferArguments } from '@unique-nft/substrate-client/tokens'; - -const args: TransferArguments = { - address: '
', - to: '
', - collectionId: 1, - tokenId: 1, -}; - -const result = await sdk.tokens.transfer.submitWaitResult(args); - -console.log(result.parsed); -``` - - - - -## Batch several different transactions - - - - -```typescript no-line-numbers -const batchTwoDifferentTransfers = async (sdk: Sdk, address: string) => { - let nonce = (await sdk.common.getNonce({address})).nonce - - const requests = await Promise.all([ - sdk.balance.transfer.build({ - address, - amount: 100, - destination: account.address, - }, {nonce: nonce++}), - sdk.tokens.transfer.build({ - address, - collectionId: 1, - tokenId: 1, - to: account.address, - }, {nonce: nonce++}), - ]) - - const results = (await Promise.all(requests.map(async r => { - const signed = await sdk.extrinsics.sign(r) - const result = await sdk.extrinsics.submit({ - ...r, - signature: signed.signature, - }) - return result - }))) as unknown as [TransferTokenParsed, BalanceTransferParsed] - - return results -} -``` - - - -## What are token permissions - -## Unique schema \ No newline at end of file diff --git a/docs/build/sdk/index.md b/docs/build/sdk/index.md index 38dd53a..3619bcc 100644 --- a/docs/build/sdk/index.md +++ b/docs/build/sdk/index.md @@ -2,318 +2,255 @@ ## Overview -Unique Network provides various blockchain connection tools in order to simplify the features implementation in your project. +The SDK facilitates seamless integration of Unique Network's capabilities into the web3 application, bypassing the need for direct low-level API interaction. It enables you to effortlessly mint collections and tokens, manage account balances, and more. -Depending on the project characteristics and the development team capabilities, you can choose the most suitable tool for you: SDK, Substrate REST or Substrate Client. +All transactions require a fee so that you can use Opal tokens for test purposes. You can get them free in [Telegram faucet bot](https://t.me/unique2faucet_opal_bot). -## Packages +[[toc]] -### SDK +## Installation -Our SDK allows integrating all Unique Network features into your web3 application without interacting with low-level API. Using SDK, you can mint collections and tokens, manage account balance, etc. -Technically, it is a REST add-on that allows you to use the same methods in a simplified form. - -### Substrate REST - -You can use a proxy HTTP service (Substrate REST) to implement server logic. -It is designed to interact with the blockchain using simple HTTP requests. -In general, this package is pretty close to SDK, but it provides you with more freedom to work with extrinsic on your side, such as: - -1. Build an unsigned extrinsic. -2. Sign and verify the extrinsic using service - (these functions should be implemented on a client for safety). -3. Submit the extrinsic. - -With Substrate REST, you can use public or self-hosted endpoints, which provides some flexibility in project and security settings. - -### Substrate Client - -Substrate Client is a JavaScript/TypeScript library that helps to interact with Unique Network directly. This approach is recommended only for experienced developers which have already worked with blockchains. This is the most low-level package that we provide. - -Substrate Client was developed as an add-on of the [Polkadot{.js} ApiPromise](https://polkadot.js.org/docs/api/start/), -extending it with simple methods to work with the Unique Network. - -However, Substrate Client can also be used with any network based on the [Substrate framework](https://substrate.io) - main modules (extrinsics, balance, query, sign, etc.) will work with them. - -Substrate Client is a low-lower connection tool that is easier than the WSS connection, but it requires more development and infrastructure support than SDK or Substrate REST. - -## How to install - -### SDK - -#### Installation +Install `@unique-nft/sdk` for Unique Network interaction and `@unique-nft/accounts` for account management. ```bash:no-line-numbers -npm install @unique-nft/sdk +npm install @unique-nft/sdk @unique-nft/accounts ``` ```bash:no-line-numbers -yarn add @unique-nft/sdk +yarn add @unique-nft/sdk @unique-nft/accounts ``` -#### Initialization - -```typescript:no-line-numbers -import Sdk, {Options} from "@unique-nft/sdk"; -const options: Options = { - baseUrl: '' -}; -const sdk = new Sdk(options); -``` -In the `baseUrl` parameter, you must pass one of the paths to [our networks](../networks/index.md): - -**Opal** : ``https://rest.unique.network/opal/v1`` - -**Quartz** : ``https://rest.unique.network/quartz/v1`` - -**Unique** : ``https://rest.unique.network/unique/v1`` - -#### Set a signer - -To be able to sign extrinsics, you need to install the [`Accounts`](https://www.npmjs.com/package/@unique-nft/accounts) package. - - - - -```bash:no-line-numbers -npm install @unique-nft/accounts -``` - - - - -```bash:no-line-numbers -yarn add @unique-nft/accounts -``` +## Creating SDK instance - - +In the `baseUrl` parameter, you must pass one of the paths to the network. For a complete list of endpoints, refer to the [reference](../../reference/sdk-endpoints.md). -Pass the `signer` in the parameters when creating the `Client` object. +You can also set a default signer; for this, you must set the seed phrase to the signer option. ```typescript:no-line-numbers -import { KeyringProvider } from '@unique-nft/accounts/keyring'; -import { KeyringOptions } from '@polkadot/keyring/types'; -import Sdk, { Options } from "@unique-nft/sdk"; +import Sdk, {Options} from "@unique-nft/sdk"; + +const baseUrl = "https://rest.unique.network/opal/v1"; +const mnemonic = ''; const options: KeyringOptions = { - type: 'sr25519', + type: "sr25519", }; const provider = new KeyringProvider(options); await provider.init(); -const signer = provider.addSeed(''); +const signer = provider.addSeed(mnemonic); -const clientOptions: Options = { - baseUrl: 'REST API URL', - signer, +const options: Options = { + baseUrl, + signer }; -const sdk = new Sdk(clientOptions); +const sdk = new Sdk(options); ``` -### Substrate REST +## Creating accounts -#### Installation -Choose install approach: [Docker](#docker) or [Public endpoints](#public-endpoints). +### Get an account from the mnemonic phrase -##### Docker +If you already have a mnemonic phrase, you can use it to get an account. Here is what the phrase looks like: -```bash:no-line-numbers -docker run -p 3000:3000 -e CHAIN_WS_URL=wss://ws-opal.unique.network uniquenetwork/web:latest -``` +`` +affair spoon other impact target solve extra range cute myself float panda +`` -See the [hub.docker.com](https://hub.docker.com/r/uniquenetwork/web) page for more details. +Here is how we can use it to get an account. -#### Public endpoints +```typescript:no-line-numbers +import { getAccountFromMnemonic } from '@unique-nft/accounts'; -You can use public endpoints for access Unique Web: +const account = await getAccountFromMnemonic({ + mnemonic: 'affair spoon other impact target solve extra range cute myself float panda', +}); +console.log(account); +``` -**Opal** : ``https://web-opal.unique.network`` +
+ +
+### Providers -### Environment variables +You can contact the provider directly if you need to get an account from a specific provider, like polkadot{.js} or Metamask. -##### CHAIN_WS_URL (required) +The following providers are supported: -```ts:no-line-numbers -// Opal -CHAIN_WS_URL = 'wss://ws-opal.unique.network' -// Quartz -CHAIN_WS_URL = 'wss://ws-quartz.unique.network' -// Unique -CHAIN_WS_URL = 'wss://ws.unique.network' -``` + + -##### SIGNER_SEED (optional) +```typescript:no-line-numbers +// The provider works directly with the chain using `KeyringPair` from the `@polkadotkeyring` package. +import { Account } from '@unique-nft/accounts'; +import { KeyringProvider } from '@unique-nft/accounts/keyring'; +import { KeyringOptions } from '@polkadot/keyring/types'; -The `SIGNER_SEED` value is used for the signing the transactions. +const options: KeyringOptions = { + type: 'sr25519', + }; + const provider = new KeyringProvider(options); + await provider.init(); -```ts:no-line-numbers -// type mnemonic here -SIGNER_SEED = 'nest have have have brave have nest nest nest body have amazing' +const signer1 = provider.addSeed(''); +const signer2 = provider.addKeyfile(''); ``` + + -##### Port (optional, default value is 3000) -```ts:no-line-numbers -PORT = 3000 -``` +```typescript:no-line-numbers +import { Account } from '@unique-nft/accounts'; +import { KeyringPair } from '@polkadot/keyring/types'; +import { + KeyringLocalOptions, + KeyringLocalProvider, + } from '@unique-nft/accounts/keyring-local'; + +const options: KeyringLocalOptions = { + type: 'sr25519', + passwordCallback: async (keyring: KeyringPair) => { + return ''; + }, + }; + const provider = new KeyringLocalProvider(options); + await provider.init(); -##### IPFS Gateway (optional) -```ts:no-line-numbers -IPFS_GATEWAY_URL = 'https://ipfs.unique.network/ipfs/' +const signer = provider.addUri('', ''); ``` -##### IPFS upload URL (optional) + + -IPFS_UPLOAD_URL allows you to specify a setting for uploading files via IPFS. -```ts:no-line-numbers -IPFS_UPLOAD_URL = 'http://192.168.100.183:5001/api/v0' +```typescript:no-line-numbers +// The provider uses the Polkadot extension (https://polkadot.js.org/extension) for the browser. +import { Web3AccountsOptions } from '@polkadot/extension-inject/types'; +import { Account } from '@unique-nft/accounts'; +import { PolkadotProvider } from '@unique-nft/accounts/polkadot'; + +const options: Web3AccountsOptions = { + accountType: ['sr25519'], + }; + const provider = new PolkadotProvider(options); + await provider.init(); + +const signer = await provider.first(); ``` -##### Cache manager (optional) + + -Extrinsics results cache time +```typescript:no-line-numbers +// The provider uses the Metamask extension (https://metamask.io/download) for the browser. +import { Account } from '@unique-nft/accounts'; +import { MetamaskProvider } from '@unique-nft/accounts/metamask'; -```ts:no-line-numbers -CACHE_TTL = 600 -``` +const provider = new MetamaskProvider(); +await provider.init(); -To set up the Redis store to cache extrinsics -```ts:no-line-numbers -REDIS_HOST = 'localhost' -REDIS_PORT = 6379 -REDIS_DB = 0 +const signer = await provider.first(); ``` -##### Prefix (optional) - -PREFIX allows you to add a global prefix to API. -By default, the prefix is empty. - -### Secondary endpoints - -You can also use a secondary connection for substrate, which allows you to use secondary endpoints. + + -Substrate endpoints +## Creating collections and NFTs + + + ```ts:no-line-numbers -// Unique -https://web-unique.unique.network/swagger/dot/ -// Quartz -https://web-quartz.unique.network/swagger/ksm/ -``` +// ... sdk initialization -#### Secondary environment variables +const { parsed, error } = await sdk.collection.create.submitWaitResult({ + name: "Test collection", + description: "My test collection", + tokenPrefix: "TST", +}); -```ts:no-line-numbers -SECONDARY_CHAIN_WS_URL = 'wss://kusama-rpc.polkadot.io' -SECONDARY_CHAIN_NAME = 'ksm' +if (error) throw Error("Error occurred while creating a collection"); +if (!parsed) throw Error("Cannot parse results"); -// or +const { collectionId } = parsed; +const collection = await sdk.collection.get({ collectionId }); -SECONDARY_CHAIN_WS_URL = 'wss://rpc.polkadot.io' -SECONDARY_CHAIN_NAME = 'ksm' +// Create NFT +await sdk.token.create({ collectionId }); +// ... ``` + + -## Substrate Client -#### Installation +## Transfer NFT - - -```bash:no-line-numbers -npm install @unique-nft/substrate-client -``` - - - - -```bash:no-line-numbers -yarn add @unique-nft/substrate-client + + +```typescript +await sdk.token.transfer({ + collectionId, + tokenId: 1, + to: "5EZDbVxdAYH6mB7uAnoUUvaXDL2LyEmYxpsEn9NWajqpQJ2W", +}); ``` -#### Initialization - -```typescript:no-line-numbers -import { createSigner } from '@unique-nft/substrate-client/sign'; -import { Client } from '@unique-nft/substrate-client'; -import fetch from 'node-fetch'; - -(async () => { - const client = await Client.create({ - chainWsUrl: 'wss://quartz.unique.network', - signer: await createSigner({ - seed: '//Alice', // Signer seed phrase if you want to sign extrinsics - }), - erc721: { // enable this option to parse ERC721 tokens - fetch: async (url: string) => { - const response = await fetch(url); - if (!response.ok) throw new Error(response.statusText); - try { - return await response.json(); - } catch (e) { - return true; - } - }, - ipfsGateways: ['https://ipfs.io', 'https://gateway.ipfs.io'], - }, - }); -})(); -``` - +## Batch several transactions -## Comparison of connection tools +You should manually increase `nonce` if you want to send several transactions in one block. -Every connection tool has several advantages and disadvantages compared to each others. - -#### SDK - -As the most user-friendly tool, the SDK has no obvious disadvantages compared to other tools. - -| Advantages | -|----------------------------------------------------------------------------| -| It is a very small package (58 kB only) | -| There is no need to use the WSS connection, that means no connection delay | -| The highest possible level of backward compatibility | -| No need for infrastructure support (in the case of using public endpoints) | -| No need to implement the transaction signature logic | - - -### Substrate REST - - -| Advantages | Disadvantages | -|-----------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------| -| This package can be used with any programming language (SDK and Substrate Client are available only for specific platforms) | Substrate REST provides fewer use cases than Substrate Client | -| Using public endpoints allows you to use public IPFS nodes | Unlike SDK, Substrate REST supposes that you have your own infrastructure | -| Using private endpoints allows you to increase the level of security for transaction signing and to use your IPFS nodes | Public endpoints don't allow you to implement safe transaction signing without JS (it is compatible only with browsers) | -| | Private endpoints don't allow you to use public IPFS and require that you build transaction signing logic in your project | - - -### Substrate client + + +```typescript no-line-numbers + let { nonce } = await sdk.common.getNonce({ address: signer.address }); -| Advantages | Disadvantages | -|---------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------| -| Compared to Substrate REST, Substrate Client already contains all the dependencies | New features are implemented in this package later, then in Substrate REST | -| The package contains all core blockchain features and methods | Relatively large package (0,5 MB), which could be critical for browser applications | -| Contains verification of the sufficiency of funds in the account for a specific transaction or confirmation of ownership of the transferred token | Doesn't contain IPFS, which means you have to upload images on your own | -| | Releases come out more often, but have less backward compatibility | -| | Contains an inner WSS connection, which means that connection delays could occur | + await Promise.all([ + sdk.balance.transfer.submitWaitResult( + { + amount: 100, + destination: "5CiRmhr6pd3YyU2VPR4ePTVxw2FddTiZeocEiiZbvq4XDACq", + }, + { nonce: nonce++ }, + ), + sdk.balance.transfer.submitWaitResult( + { + amount: 100, + destination: "5E7DCdEPC8enm49fkQ6ipkxo2EA1F3qZ5WiaaCdeppxQ9ejD", + }, + { nonce: nonce++ }, + ), + ]); +``` + + \ No newline at end of file diff --git a/docs/reference/sdk-endpoints.md b/docs/reference/sdk-endpoints.md new file mode 100644 index 0000000..5f71323 --- /dev/null +++ b/docs/reference/sdk-endpoints.md @@ -0,0 +1,7 @@ +# SDK public endpoints + +| | Endpoint | +|----------|----------| +| Unique | https://rest.unique.network/unique/v1 | +| Quartz | https://rest.unique.network/quartz/v1 | +| Opal | https://rest.unique.network/opal/v1 | diff --git a/docs/build/sdk/methods.md b/docs/reference/sdk-methods.md similarity index 100% rename from docs/build/sdk/methods.md rename to docs/reference/sdk-methods.md