Installation
Install dependencies
ParaSpell XCM SDK is the 🥇 in the ecosystem to support both PolkadotJS and PolkadotAPI.
This version of SDK uses PolkadotAPI if you wish to use PolkadotJS version please reffer to following package.
pnpm | npm install || yarn add polkadot-api
Install SDK
pnpm | npm install || yarn add @paraspell/sdk
Importing package to your project
Builder pattern:
import { Builder } from '@paraspell/sdk'
Other patterns:
import * as paraspell from '@paraspell/sdk'
const paraspell = require('@paraspell/sdk')
Interaction with further asset symbol abstraction:
import { Native, Foreign, ForeignAbstract } from '@paraspell/sdk';
Implementation
NOTES:
- PAPI version of SDK is now fully PJS-less (We removed apps/config as dependency entirely).
- You can now query foreign asset minimal deposits also.
- Since v8, amount moved closer to currency selection and specifying from and to parameters is no longer optional to save code.
- More information on v8 major breaking change: https://github.com/paraspell/xcm-tools/pull/554
- XCM SDK Now supports API Failsafe - If one endpoint doesn't work it automatically switches to the next one.
- Builder now allows you to directly disconnect API.
Latest news:
- Local transfers are now available for every currency and every chain. To try them, simply use same origin and destination parameters.
Builder pattern:
Transfer assets from Parachain to Parachain
const builder = Builder()
.from(NODE)
.to(NODE | Multilocation object )
.currency({id: currencyID, amount: amount} | {symbol: currencySymbol, amount: amount} | {symbol: Native('currencySymbol'), amount: amount} | {symbol: Foreign('currencySymbol'), amount: amount} | {symbol: ForeignAbstract('currencySymbol'), amount: amount} | {multilocation: AssetMultilocationString, amount: amount | AssetMultilocationJson, amount: amount} | {multilocation: Override('Custom Multilocation'), amount: amount} | {multiasset: {currencySelection, isFeeAsset?: true , amount: amount}})
.address(address | Multilocation object )
const tx = await builder.build()
await builder.disconnect()
Transfer assets from the Relay chain to Parachain
const builder = Builder()
.from(RELAY_NODE)
.to(NODE | Multilocation object)
.currency({symbol: 'DOT', amount: amount})
.address(address | Multilocation object)
const tx = await builder.build()
await builder.disconnect()
Transfer assets from Parachain to Relay chain
const builder = Builder()
.from(NODE)
.to(RELAY_NODE)
.currency({symbol: 'DOT', amount: amount})
.address(address | Multilocation object)
const tx = await builder.build()
await builder.disconnect()
Local transfers
const builder = Builder()
.from(NODE)
.to(NODE)
.currency({id: currencyID, amount: amount} | {symbol: currencySymbol, amount: amount} | {symbol: Native('currencySymbol'), amount: amount} | {symbol: Foreign('currencySymbol'), amount: amount} | {symbol: ForeignAbstract('currencySymbol'), amount: amount} | {multilocation: AssetMultilocationString, amount: amount | AssetMultilocationJson, amount: amount} | {multilocation: Override('Custom Multilocation'), amount: amount} | {multiasset: {currencySelection, isFeeAsset?: true , amount: amount}})
.address(address)
const tx = await builder.build()
await builder.disconnect()
Batch calls
You can batch XCM calls and execute multiple XCM calls within one call. All three scenarios (Para->Para, Para->Relay, Relay->Para) can be used and combined.
const builder = Builder()
.from(NODE)
.to(NODE_2)
.currency({currencySelection, amount})
.address(address | Multilocation object)
.addToBatch()
.from(NODE)
.to(NODE_3)
.currency({currencySelection, amount})
.address(address | Multilocation object)
.addToBatch()
const tx = await builder.buildBatch({
mode: BatchMode.BATCH_ALL
})
await builder.disconnect()
Asset claim:
const builder = Builder()
.claimFrom(NODE)
.fungible(MultilocationArray (Only one multilocation allowed) [{Multilocation}])
.account(address | Multilocation object)
const tx = await builder.build()
await builder.disconnect()
Dry run your XCM Calls:
const result = await Builder(API )
.from(NODE)
.to(NODE_2)
.currency({id: currencyID, amount: amount} | {symbol: currencySymbol, amount: amount} | {symbol: Native('currencySymbol'), amount: amount} | {symbol: Foreign('currencySymbol'), amount: amount} | {symbol: ForeignAbstract('currencySymbol'), amount: amount} | {multilocation: AssetMultilocationString, amount: amount | AssetMultilocationJson, amount: amount} | {multilocation: Override('Custom Multilocation'), amount: amount} | {multiasset: {currencySelection, isFeeAsset?: true , amount: amount}})
.address(ADDRESS)
.senderAddress(SENDER_ADDRESS)
.dryRun()
import { hasDryRunSupport } from "@paraspell/sdk-pjs";
const result = hasDryRunSupport(node)
XCM Fee (Origin and Dest.)
Following queries allow you to query fee from both Origin and Destination of the XCM Message. You can get accurate result from DryRun query(Requires token balance) or less accurate from Payment info query (Doesn't require token balance).
More accurate query using DryRun
The query is designed to retrieve you XCM fee at any cost, but fallbacking to Payment info if DryRun query fails or is not supported by either origin or destination. This query requires user to have token balance (Token that they are sending and origin native asset to pay for execution fees on origin).
NOTICE: When Payment info query is performed, it retrieves fees for destination in destination's native currency, however, they are paid in currency that is being sent. To solve this, you have to convert token(native) to token(transferred) based on price. DryRun returns fees in currency that is being transferred, so no additional calculations necessary in that case.
const fee = await Builder()
.from(ORIGIN_CHAIN)
.to(DESTINATION_CHAIN)
.currency(CURRENCY)
.address(RECIPIENT_ADDRESS)
.senderAddress(SENDER_ADDRESS)
.getXcmFee({disableFallback: true / false})
Less accurate query using Payment info
This query is designed to retrieve you approximate fee and doesn't require any token balance.
NOTICE: When Payment info query is performed, it retrieves fees for destination in destination's native currency, however, they are paid in currency that is being sent. To solve this, you have to convert token(native) to token(transferred) based on price.
const fee = await Builder()
.from(ORIGIN_CHAIN)
.to(DESTINATION_CHAIN)
.currency(CURRENCY)
.address(RECIPIENT_ADDRESS)
.senderAddress(SENDER_ADDRESS)
.getXcmFeeEstimate()
XCM Transfer info
import { getAssetBalance, getTransferInfo, getOriginFeeDetails, getTransferableAmount, getParaEthTransferFees, verifyEdOnDestination } from "@paraspell/sdk";
await getOriginFeeDetails({from, to, currency , amount, originAddress, destinationAddress, ahAddress , api , feeMargin })
await getAssetBalance({address, node, currency , api });
await getTransferableAmount({address, node, currency });
await getTransferInfo({from, to, address, destinationAddress, currency , amount, api })
await getParaEthTransferFees()
await verifyEdOnDestination(node, currency: {symbol: || id: || multilocation: .. ,amount: 100000n}, address)
Existential deposit queries
import { getExistentialDeposit } from "@paraspell/sdk";
const ed = getExistentialDeposit(node, currency?)
Convert SS58 address
import { convertSs58 } from "@paraspell/sdk";
let result = convertSs58(address, node)
Asset queries:
import { getFeeAssets, getAssetsObject, getAssetId, getRelayChainSymbol, getNativeAssets, getNativeAssets, getOtherAssets, getAllAssetsSymbols, hasSupportForAsset, getAssetDecimals, getParaId, getTNode, getAssetMultiLocation, NODE_NAMES } from '@paraspell/sdk'
getFeeAssets(node: TNode)
getAssetsObject(node: TNode)
getAssetId(node: TNode, symbol: string)
getRelayChainSymbol(node: TNode)
getNativeAssets(node: TNode)
getOtherAssets(node: TNode)
getAllAssetsSymbols(node: TNode)
hasSupportForAsset(node: TNode, symbol: string)
getAssetDecimals(node: TNode, symbol: string)
getParaId(node: TNode)
getTNode(nodeID: number, ecosystem: 'polkadot' || 'kusama' || 'ethereum')
NODE_NAMES
getAssetMultiLocation(chainFrom, { symbol: symbol } | { id: assetId })
Parachain XCM Pallet queries
import { getDefaultPallet, getSupportedPallets, getPalletIndex SUPPORTED_PALLETS } from '@paraspell/sdk';
getDefaultPallet(node: TNode)
getSupportedPallets(node: TNode)
getPalletIndex(node: TNode)
console.log(SUPPORTED_PALLETS)
💻 Tests
-
Run compilation using pnpm compile
-
Run linter using pnpm lint
-
Run unit tests using pnpm test
-
Run end-to-end tests using pnpm test:e2e
-
Run all core tests and checks using pnpm runAll
XCM SDK can be tested in Playground.
License
Made with 💛 by ParaSpell✨
Published under MIT License.
Support