SDK Changelog - v29.0.1 to v30.0.0
This guide describes changes between v29.0.1 and v30.0.0 of @polymeshassociation/polymesh-sdk, including breaking changes, new features, deprecations, and migration steps. If you're upgrading from v29, start with the Quick Migration Checklist below.
Overview
v30.0.0 is a major release that adds Polymesh chain v8 support while maintaining compatibility with chain v7. The SDK automatically detects the connected chain version at runtime and branches behavior accordingly.
Key themes in this release:
- Dual chain support (v7 and v8) — connect to either chain without changing SDK initialization code
- Account-level asset holdings — accounts can hold fungible assets and NFTs directly, not only through portfolios
- Subsidy workflow overhaul — v8 introduces approve → accept → revoke subsidy flow
- Granular agent permission groups —
TxGroupenum expanded from 10 coarse groups to 22 fine-grained groups - Dependency upgrades — Polkadot.js 16.x, polymesh-types 7.x, signing manager 4.x
- Improved transaction lifecycle — new
InBlockandFuturetransaction statuses
In this guide
Upgrading? Start with Prerequisites and Quick Migration Checklist.
Need to know what broke? See Breaking Changes.
Looking for new capabilities? Check New Features.
Want to understand behavior changes? See Modified Behavior.
Curious about removed APIs? Visit Deprecated APIs.
Prerequisites
Before upgrading, ensure your environment meets these requirements.
Supported chain versions
| Chain | Spec version threshold | SDK support |
|---|---|---|
| v7 | specVersion < 8_000_000 | Full support (existing behavior largely preserved) |
| v8 | specVersion >= 8_000_000 | Full support (new features and changed workflows) |
The SDK validates the connected chain against 7.0 || 7.1 || 7.2 || 7.3 || 8.0.
Middleware / SubQuery
If you use Middleware V2 (GraphQL), upgrade to ≥ v19.6.0-alpha.2. The SDK enforces this minimum version and will warn if your middleware is outdated.
Middleware schema changes include:
- Asset transaction history now includes
fromAccountandtoAccountfields - Claims expiry queries are fixed to correctly include non-expired claims
Dependency upgrades
Update these packages alongside the SDK:
| Package | v29.0.1 | v30.0.0 |
|---|---|---|
@polkadot/api | 11.2.1 | 16.5.2 |
@polkadot/util / util-crypto | 12.6.2 | 13.5.9 |
@polymeshassociation/polymesh-types | ^6.2.0 | ^7.4.0 |
@polymeshassociation/local-signing-manager | ^3.0.1 | ^4.1.1 |
@polymeshassociation/signing-manager-types | ^3.0.0 | ^3.7.1 |
WebSocket library change
The SDK no longer depends on the websocket npm package. It uses:
- Browser: native
WebSocketAPI - Node.js:
wspackage
If your application bundled websocket only because the SDK required it, you can remove that dependency.
Node.js
Node.js ≥ 20.0.0 is required (unchanged from v29).
Quick migration checklist
Use this checklist when upgrading from v29.0.1.
- Upgrade SDK and companion packages (Polkadot 16.x, polymesh-types 7.x, signing manager 4.x)
- Upgrade Middleware V2 to ≥ v19.6.0-alpha.2 if used
- Replace v8 subsidy flow:
subsidizeAccount→approveSubsidy+acceptSubsidy(see Subsidy workflow) - Rename settlement/instruction params:
portfolios→holders,portfolio→assetHolder,destinationPortfolio→destination(see Settlement and instruction parameter renames) - Update
InstructionAffirmation.identity→.partyand handleAccounttype (seeInstructionAffirmationtype change) - Update stored
TxGroupenum values to new granular group names (see Agent permission groups) - Handle new transaction statuses:
InBlockandFuture(see Transaction status improvements) - Use document IDs from
documents.get()for selective removal viadocuments.remove()(see Document management) - Enable balance stats (
StatType.Balance/StatType.ScopedBalance) when using percentage transfer restrictions (see Transfer restrictions and asset statistics) - Pass
expiresAttogenerateOffChainAffirmationReceipton chain v8 (see Receiver affirmation) - Guard deprecated APIs with
context.isV7checks or catchErrorCode.NotSupported(see Deprecated APIs) - For MultiSig direct execution (non-proposal), pass
asProposal: falseto fee estimation methods (see MultiSigasProposalparameter)
Breaking changes
1. Agent permission groups (TxGroup enum)
The TxGroup enum has been restructured from 10 coarse groups to 22 granular groups. Transaction tag membership is now defined in src/types/txGroupConstants.ts instead of inline enum documentation.
Removed / renamed groups:
v29 TxGroup | v30 replacement |
|---|---|
Distribution | CapitalDistribution + SettlementManagement |
ComplianceRequirementsManagement | ComplianceManagement |
New groups include: AssetDocumentManagement, AssetMetadataManagement, AssetRegistration, AuthorizationManagement, CapitalDistribution, CddRegistration, CheckpointManagement, ComplianceManagement, CorporateActionManagement, IdentityManagement, OfferingManagement, PortfolioManagement, SettlementManagement, StakingManagement, TickerManagement, TokenManagement, and others.
Migration example:
// Before (v29)
permissions: {
transactions: [
TxGroup.Distribution,
TxGroup.ComplianceRequirementsManagement,
];
}
// After (v30)
permissions: {
transactions: [TxGroup.CapitalDistribution, TxGroup.ComplianceManagement];
}
Review the full list of groups and their transaction tags in the SDK documentation or src/types/txGroupConstants.ts.
2. Settlement and instruction parameter renames
Several procedure parameter types have been renamed to support account-level asset holders.
| Parameter | v29 name | v30 name | Type change |
|---|---|---|---|
| Affirm instruction | portfolios | holders | PortfolioLike[] → AssetHolderLike[] |
| Withdraw instruction | portfolios | holders | PortfolioLike[] → AssetHolderLike[] |
| Reject instruction | portfolio | assetHolder | PortfolioLike → AssetHolderLike |
| Controller transfer | destinationPortfolio | destination | PortfolioLike → AssetHolderLike |
| NFT controller transfer | destinationPortfolio | destination | PortfolioLike → AssetHolderLike |
Migration example:
// Before (v29)
await instruction.affirm({ portfolios: [portfolio] });
await instruction.reject({ portfolio: myPortfolio });
await asset.controllerTransfer({ destinationPortfolio: targetPortfolio });
// After (v30)
await instruction.affirm({ holders: [portfolio] }); // portfolio or account
await instruction.reject({ assetHolder: myAccount });
await asset.controllerTransfer({ destination: targetAccount });
3. InstructionAffirmation type change
The affirming party is no longer always an Identity. It can now be an Account or Identity.
// Before (v29)
interface InstructionAffirmation {
identity: Identity;
status: AffirmationStatus;
}
// After (v30)
interface InstructionAffirmation {
party: Account | Identity;
status: AffirmationStatus;
}
Migration: Update any code that reads .identity on affirmation results to use .party and handle both Account and Identity types.
4. Instruction leg types
FungibleLeg and NftLeg from/to fields now use AssetHolder instead of DefaultPortfolio | NumberedPortfolio. Accounts are valid leg endpoints on chain v8.
5. TransferBreakdown.general type widening
// Before (v29)
general: TransferError[];
// After (v30)
general: (TransferError | string)[];
Chain v8 can return custom error strings not mapped to SDK TransferError enum values. Update type guards accordingly.
6. Document get() return type
// Before (v29)
documents.get(): Promise<ResultSet<AssetDocument>>
// After (v30)
documents.get(): Promise<ResultSet<AssetDocumentWithId>>
AssetDocumentWithId includes an on-chain id: BigNumber field required by the new documents.remove() method.
7. Subsidy workflow (chain v8)
On chain v8, the old authorization-based subsidy flow is deprecated.
// Before (v7 / v29)
await accountManagement.subsidizeAccount({ beneficiary, allowance });
// Beneficiary accepts via authorization
// After (v8 / v30)
await accountManagement.approveSubsidy({ beneficiary, allowance });
await accountManagement.acceptSubsidy({ subsidizer }); // called by beneficiary
// Either party can revoke before acceptance:
await accountManagement.revokeSubsidy({ beneficiary });
subsidizeAccount still works on chain v7 but is deprecated on v8.
8. MultiSig modification permissions
On v29, only the MultiSig admin identity could call modifyMultiSig. On v30, any signer on the MultiSig can modify it.
9. RoleType.CddProvider deprecated
Use RoleType.DidRegistrar instead. CDD provider role is discontinued on chain v8.
10. ModifyInstructionAffirmationParams attribute rename
Internal affirmation modification params have been renamed (affects advanced integrators building custom affirmation flows).
New features
This release introduces significant new capabilities, particularly for chain v8 support. While many features are chain-version-specific, the SDK's automatic detection means your code can remain unchanged when connecting to different chain versions.
Chain v8 dual-version support
The SDK detects chain version via Context.isV7 and Context.specVersion. These update automatically when the chain undergoes a runtime upgrade. Use this to conditionally enable v8-specific features:
const sdk = await Polymesh.connect({ nodeUrl, signingManager });
const { isV7 } = sdk.context;
if (isV7) {
// v7-specific logic
} else {
// v8-specific logic
}
A new ErrorCode.NotSupported is thrown when calling a method incompatible with the connected chain version.
Account-level asset holdings
Available on both v7 and v8. Accounts can now hold fungible assets and NFTs directly, independent of portfolios. This is a core v8 feature, with backward-compatible support on v7.
New types:
AssetHolderLike—AccountLike | PortfolioLike(convenience input type)AssetHolder—Account | DefaultPortfolio | NumberedPortfolio(concrete entity)AssetHolderId— identifier used in instruction legs
New methods:
| Method | Description | Chain |
|---|---|---|
Account.getAssetBalances() | Get all fungible asset balances held in an account | Both |
Account.getCollections() | Get NFT collections held in an account | v8 only |
Assets.transferFunds() | Transfer funds between two asset holders owned by the same identity | v8 only |
Fungible.approveAllowance() | Approve a spending allowance for another account | v8 only |
Fungible.getAllowance() | Query allowance between owner and spender | v8 only |
Modified methods that now support account-level operations:
| Method | Change |
|---|---|
FungibleSettlements.canTransfer() | from/to accept AssetHolderLike |
NonFungibleSettlements.canTransfer() | from/to accept AssetHolderLike |
Nft.getOwner() | Returns AssetHolder | null instead of Portfolio |
Identity.getInstructions() | Now includes instructions where identity owns accounts in legs |
IssueTokensParams | New optional account field (mutually exclusive with portfolioId) |
RedeemTokensParams / RedeemNftParams | New optional fromAccount field |
Subsidy management (chain v8)
v8 only. The subsidy workflow has been completely redesigned on chain v8 with explicit approve-accept-revoke flow:
| Method | Description |
|---|---|
AccountManagement.approveSubsidy() | Subsidizer approves an allowance for a beneficiary |
AccountManagement.acceptSubsidy() | Beneficiary accepts a pending subsidy |
AccountManagement.revokeSubsidy() | Subsidizer revokes a pending subsidy |
Subsidies.getPendingSubsidies() | Query pending subsidies awaiting acceptance |
See Subsidy workflow (chain v8) under Breaking Changes for migration details.
Identity registration (chain v8)
v8 only. New streamlined identity registration:
| Method | Description |
|---|---|
Identities.selfRegisterDid() | Register a new DID for the signing account without a CDD provider |
Receiver affirmation (chain v8)
v8 only. Receiver affirmation is automatic by default on chain v8. To require explicit receiver affirmation:
await identity.setMandatoryReceiverAffirmation(AffirmationRequirement.Required);
Off-chain affirmation receipts now require an expiresAt date on chain v8:
await instruction.generateOffChainAffirmationReceipt({
expiresAt: new Date('2026-12-31'),
});
Document management
Available on both v7 and v8. Incremental document operations allow you to add or remove specific documents without replacing the entire list.
| Method | Description |
|---|---|
Documents.add() | Add documents to the asset's existing list |
Documents.remove() | Remove specific documents by on-chain ID |
Documents.set() | Replace all documents (removes all existing first) |
Documents.get() | Returns documents with on-chain IDs |
Example — selective document removal:
const { data: docs } = await asset.documents.get();
const idsToRemove = docs
.filter((d) => d.name === 'old-doc.pdf')
.map((d) => d.id);
await asset.documents.remove({ documentIds: idsToRemove });
await asset.documents.add({ documents: [newDocument] });
NFT batch issuance
Available on both v7 and v8. Issue multiple NFTs in a single transaction:
await collection.batchIssue({
metadataList: [
[{ name: 'NFT 1', ... }],
[{ name: 'NFT 2', ... }],
],
});
NFT event parsing has been updated to handle chain v8's NFTHoldingsUpdated event (in addition to v7's NFTPortfolioUpdated).
Transfer restrictions and asset statistics
Improved control and reliability. Two new stat types support enhanced transfer restriction validation:
New stat types:
StatType.Balance— balance-based statistics for percentage/max-ownership restrictionsStatType.ScopedBalance— scoped balance statistics with claim-type scope
Enhanced setAssetStats / setTransferRestrictions behavior:
- Reads current active stats from chain before updating (prevents accidental stat removal)
- Only calls
setActiveAssetStatsif the stat set actually changed (reduces unnecessary on-chain operations) - Stat values are optional when enabling (defaults to 0); omit on updates to preserve current values
- Throws
NoDataChangeif no changes are needed - Fixed duplicate detection across jurisdiction and claim-type restrictions
- Fixed bug in fetching all transfer restriction exemptions
Important: When using percentage or max-ownership restrictions, you must enable StatType.Balance or StatType.ScopedBalance stats.
Transaction status improvements
Finer-grained visibility into transaction lifecycle. Two new TransactionStatus values provide better progress tracking:
| Status | When emitted |
|---|---|
InBlock | Extrinsic is included in a block (before finalization) |
Future | Extrinsic is scheduled for future execution (dispatch-after) |
Example — monitoring transaction progress:
tx.onStatusChange((status) => {
if (status === TransactionStatus.InBlock) {
// Extrinsic in block, awaiting finalization
console.log('Transaction included in block');
}
if (status === TransactionStatus.Future) {
// Scheduled for future execution
console.log('Transaction scheduled for later');
}
});
MultiSig asProposal parameter
Fee estimation and signable payload generation now accept an asProposal parameter to distinguish between direct execution and proposal creation:
// Estimate fees for direct execution (not wrapped as MultiSig proposal)
const fees = await tx.getTotalFees(false);
// Build signable payload for direct execution
const payload = await tx.toSignablePayload(metadata, false);
preRunValidation runs before fee checks and respects the asProposal context (e.g., transferPolyx validates the acting account's balance when asProposal: true).
Corporate action validation
Improved safety. Corporate action initiation now includes SDK-side validation:
- Duplicate withholding detection
- Withholding limit checks
This applies to initiateCorporateAction and configureDividendDistribution procedures.
Modified behavior
This section describes changes in how existing methods behave, without breaking their signatures. Most changes are chain-specific (v8 only) or bug fixes.
Claims (chain v8)
| Method | v7 behavior | v8 behavior |
|---|---|---|
Claims.getCddClaims() | Returns CDD claims | Throws NotSupported |
Identity.hasValidCdd() | Checks CDD validity | Returns true if DID exists |
| Claims expiry query | Could miss non-expired claims | Fixed: expiry IS NULL OR filterExpiry > now |
Historic asset transactions
BaseHistoricAssetTransaction (returned by Fungible.getTransactionHistory() and NftCollection.getTransactionHistory()) now includes account-level transfer details:
fromAccount: Account | nulltoAccount: Account | null
These fields are populated when using Middleware V2 (≥ v19.6.0-alpha.2).
Default portfolio ID assignment
Bug fix. Fixed incorrect ID assignment to the default portfolio.
Staking controller (chain v8)
The controller argument to setStakingController is ignored on chain v8 — the stash account becomes its own controller.
Invite permissions default
Bug fix. Corrected default invite permissions to use assets: key instead of tokens:.
Deprecated APIs
The following APIs are deprecated. On chain v8, calling deprecated methods throws ErrorCode.NotSupported. On chain v7, they continue to work but should not be used in new code.
Subsidy
| Deprecated | Replacement |
|---|---|
AccountManagement.subsidizeAccount() | approveSubsidy() + acceptSubsidy() |
Migration: See Subsidy workflow (chain v8) for details.
CDD claims
| Deprecated | Notes |
|---|---|
Claims.getCddClaims() | CDD claims discontinued on v8 |
Identity.hasValidCdd() | Behavior changed on v8 (see Modified behavior) |
Child identities
| Deprecated | Notes |
|---|---|
Identities.getChildIdentity() | Child identities discontinued on v8 |
Identities.createChild() | Child identities discontinued on v8 |
All ChildIdentity methods | Child identities discontinued on v8 |
Instruction affirmation withdrawal
| Deprecated | Replacement |
|---|---|
Instruction.withdraw() | Use reject() instead |
Instruction.withdrawAsMediator() | Use rejectAsMediator() instead |
InstructionAffirmationOperation.Withdraw | Deprecated enum value |
InstructionAffirmationOperation.WithdrawAsMediator | Deprecated enum value |
Other
| Deprecated | Replacement / notes |
|---|---|
RoleType.CddProvider | RoleType.DidRegistrar |
AcceptPrimaryKeyRotationParams.cddAuth | No longer needed on v8 |
NftControllerTransferParams.destinationPortfolio | destination: AssetHolderLike |
AuthorizationType.AddRelayerPayingKey | OldAddRelayerPayingKey |
Bug fixes
| Area | Fix |
|---|---|
| Transfer restrictions | Fixed setTransferRestrictions input validation |
| Transfer restrictions | Fixed fetching all transfer restriction exemptions |
| Claims | Fixed claims expiry query to include non-expired claims |
| Default portfolio | Fixed incorrect ID assignment to default portfolio |
| Invite permissions | Fixed default permissions key (tokens: → assets:) |
| MultiSig fees | Fixed payer fallback when primary account has no identity |
| v7 types | Explicit v7 type handling in dual-version code paths |
Version compatibility matrix
Quick reference for version compatibility:
| SDK version | Chain v7 | Chain v8 | Middleware V2 | Polkadot.js |
|---|---|---|---|---|
| v29.0.1 | ✅ | ❌ | ≥ v19.3.0 | 11.2.1 |
| v30.0.0 | ✅ | ✅ | ≥ v19.6.0-alpha.2 | 16.5.2 |