Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 15 additions & 3 deletions .env.sample
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
# Connection (required by all examples via src/common/client.ts)
POLYMESH_NODE_URL=ws://localhost:9944
MIDDLEWARE_LINK=http://localhost:3000/testnet/graphql
MIDDLEWARE_KEY=XxxXxxXxxXxxXxxXxxXxxXxxXxxXxxXxxX
MIDDLEWARE_LINK=http://localhost:3000
MIDDLEWARE_KEY= # not needed with middleware v2

# Primary signing account mnemonic (required by all examples)
ACCOUNT_SEED=//Alice
BOB_DID=0x0200000000000000000000000000000000000000000000000000000000000000

# Secondary identity DID (claims, customClaims, compliance, settlements,
# portfolioCustodians, externalAgents, securityTokenCaa, assetInviteAgent)
BOB_DID=0x0200000000000000000000000000000000000000000000000000000000000000

# Dividend currency asset ID (dividendDistributions.ts)
DIVIDEND_CURRENCY=

# Beneficiary account mnemonic (subsidy.ts)
BOB_SEED=//Bob
43 changes: 29 additions & 14 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,47 +11,62 @@ jobs:
name: Linting
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- uses: actions/setup-node@v1
- uses: actions/checkout@v4
- name: Enable Corepack
run: corepack enable
- uses: actions/setup-node@v4
with:
node-version: '22.x'
node-version: "22.x"
- name: install dependencies
run: yarn --frozen-lockfile
run: yarn install --immutable
- name: lint
run: yarn lint

test:
name: Testing
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- uses: actions/setup-node@v1
- uses: actions/checkout@v4
- name: Enable Corepack
run: corepack enable
- uses: actions/setup-node@v4
with:
node-version: '22.x'
node-version: "22.x"
- name: install dependencies
run: yarn --frozen-lockfile
run: yarn install --immutable
- name: test
run: yarn test

release:
name: Building and releasing project
runs-on: ubuntu-latest
needs: [lint, test]
if: github.event_name == 'push'
permissions:
contents: write # push release commits, tags, create GitHub Releases
issues: write # @semantic-release/github comments on resolved issues
pull-requests: write # @semantic-release/github comments on merged PRs
id-token: write # OIDC token for npm trusted publishing
steps:
- uses: actions/checkout@v1
- uses: actions/setup-node@v1
- uses: actions/checkout@v4
- name: Enable Corepack
run: corepack enable
- uses: actions/setup-node@v4
with:
node-version: '22.x'
node-version: "22.x"
- name: install dependencies
run: yarn --frozen-lockfile
run: yarn install --immutable
- name: build
run: |
yarn build:ts
cp package.json dist/package.json
cp README.md dist/README.md
cp yarn.lock dist/yarn.lock
cp -R node_modules dist/node_modules
cp .releaserc.js dist/.releaserc.js
- name: release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
GITHUB_TOKEN: ${{ secrets.ASSOCIATION_RELEASE_TOKEN }}
run: |
cd dist
yarn --frozen-lockfile
Expand Down
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ npm-package/
coverage/
test.ts
docs/
.env
.env
.yarn
File renamed without changes.
1 change: 1 addition & 0 deletions .yarnrc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
nodeLinker: node-modules
164 changes: 148 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,34 +1,166 @@
## Description
# Polymesh SDK Examples

Example project that demonstrate how to use Polymesh SDK along with some of its use cases
Example scripts demonstrating how to use the [Polymesh SDK](https://github.com/PolymeshAssociation/polymesh-sdk) against a Polymesh node. These examples target **chain v8** and SDK **v30**.

Each file under `src/examples/` is a self-contained script you can run with `yarn run-example`. They connect via `src/common/client.ts`, sign transactions with `@polymeshassociation/local-signing-manager`, and cover common workflows: assets, portfolios, settlements, compliance, STOs, staking, and more.

## Requirements

- **Node.js** 20+ (matches `@polymeshassociation/polymesh-sdk` engine requirement)
- **Yarn** 4 (see `packageManager` in `package.json`)
- A running **Polymesh node** (WebSocket endpoint)
- **Polymesh middleware v2** (GraphQL) — required by the SDK for most queries

For local development, the [Polymesh local node](https://developers.polymesh.network/docs/development/) and its bundled middleware are the easiest starting point.

## Setup

### Requirements
```bash
yarn
cp .env.sample .env
# Edit .env for your node, middleware, and identities
```

## Environment variables

Copy `.env.sample` to `.env` and configure:

| Variable | Required | Description |
|----------|----------|-------------|
| `POLYMESH_NODE_URL` | Yes | WebSocket URL of the Polymesh node (e.g. `ws://localhost:9944`) |
| `MIDDLEWARE_LINK` | Yes | URL of the Polymesh GraphQL middleware (e.g. `http://localhost:3000`) |
| `MIDDLEWARE_KEY` | No | API key for middleware v2 (usually empty locally) |
| `ACCOUNT_SEED` | Yes | Mnemonic of the primary signing account (e.g. `//Alice`) |
| `BOB_DID` | For some examples | DID of a secondary identity used as a target (custodian, claim target, agent invitee, etc.) |
| `BOB_SEED` | For `subsidy.ts` | Mnemonic of the subsidy beneficiary account (e.g. `//Bob`) |
| `DIVIDEND_CURRENCY` | For dividend/STO examples | Asset ID of the currency used for dividends and STO raising |

**Tip:** `BOB_DID` must exist on the chain you connect to. On a fresh local node, use a DID that is actually registered — it may differ from the default in `.env.sample`. The account behind `BOB_SEED` does not have to control `BOB_DID`; examples that need Bob to *sign* use `BOB_SEED`, while examples that only need a target identity use `BOB_DID`.

- node.js version 14.x
- yarn version 1.x
## Running examples

### Installing Dependencies
```bash
yarn run-example <path-to-example> [arguments]
```

Examples load variables from `.env` automatically (`dotenv/config`).

### Argument formats

Most asset-scoped examples take a **ticker or asset ID** as the first argument:

```bash
$ yarn
yarn run-example src/examples/assetBalance.ts MY_TICKER
yarn run-example src/examples/assetBalance.ts 2871e9af-9928-87f4-92fa-67b57ddf5068
```

### Environment Variables
Some examples use **key=value** arguments (see the header comment in each file):

```bash
yarn run-example src/examples/assets/issueTokens.ts asset=MY_TICKER amount=1000
yarn run-example src/examples/subsidy.ts account=5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty
```

### Examples with dependencies

A few scripts assume prior setup or a specific run order:

| Run first | Then |
|-----------|------|
| `createToken.ts` | Asset-scoped examples (to create an asset you control) |
| `stos.ts` | `investInSto.ts` (needs a live offering) |

STO example with optional close step:

```bash
POLYMESH_NODE_URL=## websocket URL for a Polymesh node ##
MIDDLEWARE_LINK=## URL for an instance of the Polymesh GraphQL Middleware service ##
MIDDLEWARE_KEY=## API key for the Middleware GraphQL service ##
ACCOUNT_SEED=## mnemonics of a signer ##
BOB_DID=## DID of an identity to be used as target (a Portfolio Custodian, a Claim target etc.) for various use cases ##
yarn run-example src/examples/stos.ts <ASSET_ID>
yarn run-example src/examples/stos.ts <ASSET_ID> --close # also closes the offering at the end
yarn run-example src/examples/investInSto.ts <ASSET_ID>
```

## Running the app
Dividend distributions accept an optional currency as a second argument or via `DIVIDEND_CURRENCY`:

```bash
$ yarn run-example <path-to-example-file>
yarn run-example src/examples/dividendDistributions.ts <ASSET_ID> <CURRENCY_ASSET_ID>
```

NOTE: You may be required to pass a second argument such as a ticker or a secondary account in some of the examples.
## Example index

### Assets

| Example | Arguments | Description |
|---------|-----------|-------------|
| `assetBalance.ts` | asset | Query balance for an asset |
| `assetMetadata.ts` | asset | Register and manage asset metadata |
| `assetInviteAgent.ts` | asset | Invite an external agent |
| `createToken.ts` | ticker | Create a new fungible asset |
| `assets/issueTokens.ts` | `asset=`, `amount=` | Issue tokens |
| `assets/redeemTokens.ts` | `asset=`, `amount=` | Redeem tokens |
| `assets/getHolders.ts` | `asset=` | List asset holders |
| `transferRestrictions.ts` | asset | Set transfer restrictions |

### Portfolios & settlements

| Example | Arguments | Description |
|---------|-----------|-------------|
| `portfolios.ts` | asset (optional) | Create, rename, move funds, redeem, delete portfolios |
| `portfolioCustodians.ts` | — | Assign and manage portfolio custodians |
| `settlements.ts` | asset (optional) | Create a venue, add an instruction, affirm |
| `batchTransactions.ts` | — | Batch multiple transactions |

### Identity & permissions

| Example | Arguments | Description |
|---------|-----------|-------------|
| `manageSecondaryKeys.ts` | account (optional) | Invite and manage secondary signing keys |
| `externalAgents.ts` | asset | Manage external agent groups |
| `subsidy.ts` | `account=` | Approve, accept, and manage subsidies |
| `staking.ts` | — | Bond, nominate, unbond, set payee/controller |

### Compliance & claims

| Example | Arguments | Description |
|---------|-----------|-------------|
| `compliance.ts` | asset | Set compliance requirements and trusted issuers |
| `claims.ts` | asset | Add and revoke claims |
| `customClaims.ts` | `name=` | Create and use custom claim types |

### Corporate actions & STOs

| Example | Arguments | Description |
|---------|-----------|-------------|
| `checkpoints.ts` | asset | Create and inspect checkpoints |
| `dividendDistributions.ts` | asset, currency (optional) | Launch and manage dividend distributions |
| `securityTokenCaa.ts` | asset | Assign a corporate actions agent |
| `stos.ts` | asset, currency (optional), `--close` | Launch, modify, freeze, and close an STO |
| `investInSto.ts` | asset | Invest in a live offering |

## Local development notes

- **Use an asset you control.** Alice may not have permissions on pre-existing chain assets. Run `createToken.ts` first, or pass an asset ID you own.
- **Re-runs are mostly safe.** Many examples use timestamp suffixes or skip steps gracefully when state already exists (duplicate portfolio names, already bonded, pending subsidy, etc.).
- **`//Alice` and `//Bob` may share a DID** on a default local chain. `investInSto.ts` handles this by registering a new investor identity when needed.
- **Settlement timing.** Instructions with a far-future `endBlock` will not settle until that block. Examples that need immediate settlement omit `endBlock`.
- **CDD claims on v8.** `claims.ts` skips CDD-specific queries that are no longer supported on chain v8.

## Troubleshooting

| Symptom | Likely cause |
|---------|----------------|
| `doesn't have the required permissions` | The signing identity is not an agent/owner of the asset |
| `No asset exists with asset ID` | Wrong asset ID for this chain, or asset was never created |
| `No live offerings found` | Run `stos.ts` before `investInSto.ts` |
| `SameSenderReceiver` | Investor and asset owner are the same identity |
| `Instruction is already affirmed` | Harmless on re-run; the example skips duplicate affirmation |
| Middleware / connection errors | Check `POLYMESH_NODE_URL` and `MIDDLEWARE_LINK` are reachable |

## Project structure

```
src/
common/
client.ts # Shared Polymesh connection helper
assets.ts # Asset lookup helpers
utils.ts # Parsing, logging, and type helpers
examples/ # Runnable example scripts
```
38 changes: 21 additions & 17 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,27 @@
"types": "dist/index.d.ts",
"author": "Polymath Studios Inc.",
"license": "ISC",
"engines": {
"node": ">=20.0.0"
},
"scripts": {
"test": "jest --coverage --passWithNoTests",
"build:ts": "ttsc -b",
"build:ts": "tsc && tsc-alias",
"build:docs": "typedoc src",
"commit": "npx git-cz",
"semantic-release": "semantic-release",
"lint": "eslint src --ext .js,.jsx,.ts,.tsx",
"run-example": "npx ts-node@8.2.0 -r tsconfig-paths/register -r dotenv/config",
"run-example": "ts-node -r tsconfig-paths/register -r dotenv/config",
"format": "cross-env prettier-eslint $PWD\"/src/**/*.{ts,tsx,js,jsx,json,css,md}\" --write",
"prepare": "is-ci || husky install"
},
"devDependencies": {
"@commitlint/cli": "^17.7.1",
"@commitlint/config-conventional": "^17.7.0",
"@ovos-media/ts-transform-paths": "^1.7.18-1",
"@semantic-release/git": "^8.0.0",
"@semantic-release/git": "^10.0.1",
"@types/bluebird": "^3.5.38",
"@types/jest": "29.5.4",
"@types/node": "^18.15.11",
"@types/jest": "^29.5.14",
"@types/node": "^20.19.8",
"@typescript-eslint/eslint-plugin": "6.5.0",
"@typescript-eslint/parser": "6.5.0",
"cross-env": "^7.0.3",
Expand All @@ -39,21 +41,22 @@
"eslint-plugin-simple-import-sort": "^10.0.0",
"husky": "8.0.3",
"is-ci": "3.0.1",
"jest": "29.6.4",
"lint-staged": "14.0.1",
"jest": "^29.7.0",
"lint-staged": "15.2.10",
"prettier": "2.8.8",
"prettier-eslint": "15.0.1",
"prettier-eslint-cli": "7.1.0",
"semantic-release": "^19.0.2",
"ts-jest": "^29.1.1",
"tsconfig-paths": "^3.9.0",
"ttypescript": "^1.5.15",
"typedoc": "^0.23.5",
"typescript": "4.6.2"
"semantic-release": "^25.0.3",
"ts-jest": "^29.4.0",
"ts-node": "10.9.1",
"tsc-alias": "^1.8.16",
"tsconfig-paths": "^4.2.0",
"typedoc": "^0.28.8",
"typescript": "5.8.3"
},
"dependencies": {
"@polymeshassociation/local-signing-manager": "^3.1.0",
"@polymeshassociation/polymesh-sdk": "27.3.0-alpha.1",
"@polymeshassociation/local-signing-manager": "^4.1.1",
"@polymeshassociation/polymesh-sdk": "30.0.0",
"bluebird": "^3.7.2",
"dotenv": "^16.0.3"
},
Expand All @@ -64,5 +67,6 @@
},
"publishConfig": {
"access": "public"
}
},
"packageManager": "yarn@4.12.0+sha512.f45ab632439a67f8bc759bf32ead036a1f413287b9042726b7cc4818b7b49e14e9423ba49b18f9e06ea4941c1ad062385b1d8760a8d5091a1a31e5f6219afca8"
}
2 changes: 1 addition & 1 deletion src/common/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ let api: Polymesh;
*/
export async function getClient(mnemonic?: string): Promise<Polymesh> {
const localSigningManager = await LocalSigningManager.create({
accounts: [mnemonic ? { mnemonic } : { uri: '//Alice' }],
accounts: [mnemonic ? { mnemonic } : { mnemonic: '//Alice' }],
});

if (!api) {
Expand Down
Loading
Loading