Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
0ffd3ee
Tx module + improvements to other modules & test setup
Lezek123 Mar 28, 2025
c90bf1f
Deploy docs workflow: only from main branch
Lezek123 Mar 28, 2025
70f60e0
Docs: Use joystream.dev endpoints as examples
Lezek123 Mar 28, 2025
69cf590
Update tarball
Lezek123 Mar 28, 2025
8cd4661
Add more meta transactions
Lezek123 Mar 28, 2025
d630019
Fix test setup, add some meta transactions tests
Lezek123 Mar 28, 2025
12d79b1
Update tarball
Lezek123 Mar 28, 2025
9a68150
Cleanup resources after tests
Lezek123 Mar 28, 2025
d624587
Attempt to fix CI
Lezek123 Mar 28, 2025
7847383
Attempt to fix QN disconnection logic
Lezek123 Mar 28, 2025
b17b652
Adjust disconnecting in blockUtils tests
Lezek123 Mar 28, 2025
31291e4
Another attempt to fix CI
Lezek123 Mar 28, 2025
79af155
Tests: Increase timeouts and limit max concurrency
Lezek123 Mar 28, 2025
1eff0ac
QN: Use lazy ws connection
Lezek123 Mar 28, 2025
1fdfaeb
Documentation (query module): make storageSquid snippets runnable, ad…
Lezek123 Apr 1, 2025
0061c67
Query module: Separate BlockProcessorApi and MetadataProcessorApi
Lezek123 Apr 1, 2025
5dc8fb6
Update docs, improve setup, small fixes in multiple modules
Lezek123 Apr 4, 2025
ce33415
Fix snippet tests
Lezek123 Apr 4, 2025
eda5bfd
Update docs workflow
Lezek123 Apr 4, 2025
f59f84f
Snippets: Disconnect from API after tests
Lezek123 Apr 4, 2025
4b6ba95
Attempt to fix test in CI
Lezek123 Apr 4, 2025
9187064
Fix docs deployment
Lezek123 Apr 7, 2025
a9f3ab4
Fix docs build
Lezek123 Apr 7, 2025
fff2649
Assets module: Calculating tx costs
Lezek123 May 5, 2025
012c6ad
Assets module docs + fix a couple of bugs
Lezek123 May 7, 2025
9e3fe19
Run pre-push script
Lezek123 May 8, 2025
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
7 changes: 4 additions & 3 deletions .github/workflows/deploy-docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ on:
push:
branches:
- main
- dev
workflow_dispatch:

jobs:
Expand All @@ -19,11 +18,13 @@ jobs:
with:
node-version-file: 'package.json'
- name: Install dependencies
working-directory: ./docs
run: yarn install --immutable
- name: Run codegen
run: yarn codegen
- name: Run build
working-directory: ./docs
run: yarn build
- name: Run docs build
run: yarn build:docs
- name: Upload build artifacts
uses: actions/upload-pages-artifact@v3
with:
Expand Down
9 changes: 5 additions & 4 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
- name: Run build
run: yarn build
- name: Setup testing environment
run: yarn test:setup
run: yarn test:setup:up
- name: Run tests
run: yarn test:sdk
test-snippets:
Expand All @@ -36,8 +36,9 @@ jobs:
node-version-file: 'package.json'
- name: Install dependencies
run: yarn install --immutable
- name: Install /docs dependencies
working-directory: ./docs
run: yarn install --immutable
- name: Run codegen
run: yarn codegen
- name: Build code
run: yarn build
- name: Test snippets
run: yarn test:snippets
73 changes: 73 additions & 0 deletions docs/docs/core/_tx-flow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
```mermaid
---
config:
look: classic
layout: dagre
---

flowchart TB
S_Un["Status: Unsigned"] ==> A_Si{"Signing"}
A_Si ==> S_Si["Status: Signed"]
S_Si ==> E_Si(["Event: signed"])
E_Si ==> A_Se{"Sending"}
A_Se ==> S_Se["Status: Sent"]
S_Se ==> E_Se(["Event: sent"])
E_Se ==> A_Bl{"Waiting for block inclusion"}
A_Bl ==> S_Bl["Status: InBlock"]
S_Bl ==> E_Bl(["Event: in_Block"])
E_Bl ==> A_Fi{"Waiting for finalization"}
A_Fi ==> S_Fi["Status: Finalized"]
S_Fi ==> E_Fi(["Event: finalized"])
E_Fi ==> A_Pr{"Waiting for processing"}
A_Pr ==> E_Pr(["Event: processed_by..."])
A_Si --> E_Si_er(["Event: error"])
A_Se --> S_Re["Status: Rejected"]
S_Re --> E_Se_er(["Event: error"])
A_Bl --> S_Us["Status: Usurped"] & S_Dr["Status: Dropped"] & S_Iv["Status: Invalid"]
S_Us --> E_Bl_er(["Event: error"])
S_Dr --> E_Bl_er
S_Iv --> E_Bl_er
A_Fi --> E_Re(["Event: retracted"]) & S_Ft["Status: FinalityTimeout"]
E_Re --> A_Bl
S_Ft --> E_Fi_er(["Event: error"])
S_Bl --> E_Bl_de(["Event: error (DispatchError)"])
E_Bl_de --> E_Bl
S_Fi --> E_Fi_de(["Event: error (DispatchError)"])
E_Fi_de --> E_Fi
E_Si_er ~~~ S_Re
E_Bl_er ~~~ S_Ft
A_Si:::Sky
S_Un:::Pine
S_Si:::Pine
E_Si:::Aqua
A_Se:::Pine
A_Se:::Sky
S_Se:::Pine
E_Se:::Aqua
A_Bl:::Sky
S_Bl:::Pine
E_Bl:::Aqua
A_Fi:::Sky
S_Fi:::Pine
E_Fi:::Aqua
A_Pr:::Sky
E_Pr:::Aqua
E_Si_er:::Peach
S_Re:::Rose
E_Se_er:::Peach
S_Us:::Rose
S_Dr:::Rose
S_Iv:::Rose
E_Bl_er:::Peach
E_Re:::Ash
S_Ft:::Rose
E_Fi_er:::Peach
E_Bl_de:::Peach
E_Fi_de:::Peach
classDef Pine stroke-width:1px, stroke-dasharray:none, stroke:#254336, fill:#27654A, color:#FFFFFF
classDef Peach stroke-width:1px, stroke-dasharray:none, stroke:#FBB35A, fill:#FFEFDB, color:#8F632D
classDef Sky stroke-width:1px, stroke-dasharray:none, stroke:#374D7C, fill:#E2EBFF, color:#374D7C
classDef Aqua stroke-width:1px, stroke-dasharray:none, stroke:#46EDC8, fill:#DEFFF8, color:#378E7A
classDef Rose stroke-width:1px, stroke-dasharray:none, stroke:#FF5978, fill:#FFDFE5, color:#8E2236
classDef Ash stroke-width:1px, stroke-dasharray:none, stroke:#999999, fill:#EEEEEE, color:#000000
```
203 changes: 203 additions & 0 deletions docs/docs/core/assets.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
---
sidebar_position: 4
---

import consts from '@site/src/consts'
import { GhLink } from '@site/src/components/GhLink';
import { GlossaryLink } from '@site/src/components/Glossary';
import CodeBlock from '@theme/CodeBlock';
import hapiToJoy from '!!raw-loader!../../src/snippets/assets/hapiToJoy.ts';
import joyToHapi from '!!raw-loader!../../src/snippets/assets/joyToHapi.ts';
import treasuryAccounts from '!!raw-loader!../../src/snippets/assets/treasuryAccounts.ts';
import videoCosts from '!!raw-loader!../../src/snippets/assets/createVideoCosts.ts';
import extrinsicBalancesEffect from '!!raw-loader!../../src/snippets/assets/extrinsicBalancesEffect.ts';
import batchSupport from '!!raw-loader!../../src/snippets/assets/batchSupport.ts';
import mergingCosts from '!!raw-loader!../../src/snippets/assets/mergingCosts.ts';
import balances from '!!raw-loader!../../src/snippets/assets/balances.ts';

# Assets module

The assets module provides a set of utilities related to balances, fees, vesting, locks and stakes on Joystream.

Some of the available features include:

- Retrieving account balances available for different purposes (ie. making transfers, paying different kinds of fees, staking etc.)
- Conversion between `JOY` and `HAPI`, supporting multiple variable types (`number`, `BigInt`, `string`, `BN`)
- Establishing all costs associated with executing a specific runtime extrinsic (tx fees, platform fees, bloat bonds, deposits, transfers etc.), how they would
affect existing balances and whether an account has sufficient funds to cover them.

## Conversion

### HAPI to JOY

<CodeBlock language="typescript" live>{hapiToJoy}</CodeBlock>

### JOY to HAPI

<CodeBlock language="typescript" live>{joyToHapi}</CodeBlock>

## Constants

The following constants can be imported from `@joystream/sdk-core/assets`:

```typescript
// Number of decimal places that JOY token supports
export const JOY_DECIMALS = 10

// How much HAPI (smallest JOY token units) makes up 1 JOY
export const HAPI_PER_JOY = 10 ** JOY_DECIMALS

// Joystream existential deposit (in HAPI)
export const EXISTENTIAL_DEPOSIT = BigInt(266_666_560)
```

## Treasury accounts

The assets module exports treasury accounts of different runtime modules, which are typically used to store bloat bonds and other deposits:

<CodeBlock language="typescript" live>{treasuryAccounts}</CodeBlock>

## AssetsManager

The main way of interacting with the assets module is through the `AssetsManager` class.
It allows you to retrieve account balances, estimate extrinsic costs and more...

### Initializing

#### Standalone

```typescript
import { createApi } from '@joystream/sdk-core/chain'
import { AssetsManager } from '@joystream/sdk-core/assets'

const api = await createApi(`wss://mainnet.joystream.dev/rpc`)
const assets = new AssetsManager(api)
```

#### via JoystreamToolbox

```typescript
import { createJoystreamToolbox } from '@joystream/sdk-core/toolbox'

const joystreamToolbox = await createJoystreamToolbox({
nodeWsEndpoint: 'wss://mainnet.joystream.dev/rpc',
// ...
})
const { assets } = joystreamToolbox
```

### Checking account balances

The `AssetsManager` provides a simple way to retrieve account balances in a format that's typically more useful (than, for example, `api.derive.balances.all`) in context of Joystream:

<CodeBlock language="typescript" live>{balances}</CodeBlock>

#### Balances type

The balances are represented by the following abstraction:

```typescript
export type Balances = {
// All funds, including locked and reserved
total: bigint
// All funds EXCEPT reserved
free: bigint
// All funds that can be used to pay transaction fees and other fee-like costs
feeUsable: bigint
// All funds that are free to be transferred to another account
transferrable: bigint
}
```

This representation is directly tied to the [abstraction of a `Cost`](#costs-interface) which is described later in this document.

:::info
The `Balances` representation is still a work in progress and will be expanded with information about vesting and active stakes/locks in the future.
:::

### Estimating extrinsic costs

Imagine a user of your application wants to add a new video to Joystream.

Executing `content.createVideo` extrinsic involves paying multiple different costs, such as:

- **Transaction fee** - based on the extrinsic arguments and size,
- **Data fee** - based on the size of associated video assets (thumbnail, video media file, subtitles etc.),
- **Data object bloat bond** - based on the number of assets associated with the video and the current bloat bond value in the runtime storage module,
- **Video bloat bond** - based on the value in the runtime content module.

Typically you would need to calculate those costs in advance in order to:

- Inform the user about them,
- Validate whether the user has sufficient balance to cover them.

`AssetsManager` provides a unified interface for dealing with a variety of different costs and allows you display detailed summaries and validate balances without having to write your own logic for each Joystream extrinsic separately.

Take a look at the following example:

<CodeBlock language="typescript" live>{videoCosts}</CodeBlock>

#### Costs interface

If you run the code above, you will notice that each of the listed costs conforms to the following interface:

```typescript
export interface Cost {
// What kind of cost is this (for example: MembershipFee)
kind: CostKind
// Whether paying this cost requires the account to stay alive
// (and therefore its totalBalance to stay above EXISTENTIAL_DEPOSIT)
requiresKeepAlive: boolean
// What happens with the funds? (ie. are they burned? deposisted? transferred?)
destiny: FundsDestiny
// Which balance type is used to pay the the cost (eg. free, feeUsable, transferrable)
paidFrom: BalanceType
// Value in HAPI
value: bigint
}
```

For more details and exact definitions of `CostKind`, `BalanceType` and `FundsDestiny` types, see <GhLink to="packages/core/src/assets/types.ts" />.

Having such detiled and flexible abstraction of a `Cost` enables multiple other features that `AssetsManager` provides (see more examples below).

#### Checking how costs affect balances

`AssetsManager` allows you to check how the estimated extrinsic costs will affect different types of balances of a given account:

<CodeBlock language="typescript" live>{extrinsicBalancesEffect}</CodeBlock>

#### Ensuring sufficient balances

To check whether an account has sufficient balances to cover all provided [costs](#costs-interface), you can simply use the `canPay` method:

```typescript
const hasSufficientFunds = await assets.canPay(alice, costs)

if (!hasSufficientFunds) {
console.log("Can't cover the extrinsic costs!")
} else {
console.log('OK!')
}
```

#### Estimating costs of multiple extrinsics

If your application/script sends multiple extrinsics at once, either because it runs some operations in batches or deals with more complex, multi-step workflows, you may want to estimate the costs of all those extrinsics together beforehand.

:::warning
**Not all costs can be accurately predicted in advance!** (especially if one of the extrinsics you send affects the cost(s) of another)

Imagine a scenario where you batch multiple `projectToken.buyOnAmm` calls for the same token.
Each of those calls will increase the price of the token and affect the costs of subsequent calls. `AssetsManager` will not take those intermediate runtime state changes into account, leading to an underestimation of the total cost.
:::

`AssetsManager` supports all available batch extrinsics (`utility.batch`, `utility.forceBatch`, `utility.batchAll`), so if you're using them to group your extrinsics together, you can simply pass the batch extrinsic to the `costsOf` method:

<CodeBlock language="typescript" live>{batchSupport}</CodeBlock>

Alternatively, if you're sending extrinsics one-by-one, you can estimate the costs separately and then merge them into a single array:

<CodeBlock language="typescript" live>{mergingCosts}</CodeBlock>

This costs representation will work perfectly fine with methods like `canPay`, `estimateBalancesAfter` etc.
File renamed without changes
File renamed without changes
Loading
Loading