Full Pallet API Reference - v8.0 to v8.1.2
Every structural API change between Polymesh chain v8.0.2 and v8.1.2: each call, event, error, storage item and runtime API that was added, renamed or had its behaviour change. It complements the narrative pages in the v8.0 → v8.1.2 changelog.
Scope:
- No pallets were added or removed, and no constants changed.
transaction_versionis unchanged at8. Existing signing code needs no update.- Nothing was removed. The only rename is one
Settlementerror, which retains its index. OneStoerror is added in v8.1.2, at the end of its variant list. pallet-precompilesis not a runtime pallet — it plugs intopallet_revive::Config::Precompiles, takes no pallet index and adds nothing to metadata. The precompile interfaces are not part of this reference.
Summary
| Pallet | Calls | Events | Errors | Storage |
|---|---|---|---|---|
| Asset | 5 added | 3 added | 4 added | 2 added |
| Nft | 3 added | 3 added | 3 added | 3 added |
| Portfolio | — | — | 1 added | 3 added |
| Settlement | — | — | 1 renamed | — |
| Sto | — | — | 1 added | — |
Five calls change behaviour or cost without changing their signature: MultiSig::create_multisig, Portfolio::quit_portfolio_custody, ExternalAgents::create_group/set_group_permissions, Sto::invest and Portfolio::move_portfolio_funds. See Behaviour changes without a signature change.
Storage versions: pallet-nft 7 → 8, pallet-portfolio 4 → 5. Both are migrated automatically — see Other Runtime Changes.
The AssetHolder type
Several new calls take an AssetHolder, an enum introduced in v8.0 and used more widely here:
enum AssetHolder {
Portfolio(PortfolioId),
Account(AccountId32),
}
Freezing and controller transfers act on a holder in either form. Because the two forms live in different pallets' storage, an account's frozen state is in Asset and a portfolio's is in Portfolio.
Asset
Calls
| Index | Call | Arguments |
|---|---|---|
| 38 | set_frozen_tokens | asset_id: AssetId, asset_holder: AssetHolder, amount: Balance |
| 39 | set_holder_frozen | asset_holder: AssetHolder, asset_id: AssetId, freeze: bool |
| 40 | controller_transfer_to | asset_id: AssetId, value: Balance, source: AssetHolder, destination: AssetHolder |
| 41 | freeze_partial_tokens | asset_id: AssetId, asset_holder: AssetHolder, amount: Balance |
| 42 | unfreeze_partial_tokens | asset_id: AssetId, asset_holder: AssetHolder, amount: Balance |
All five require the caller to be an external agent of the asset with the relevant permission.
set_frozen_tokens, freeze_partial_tokens and unfreeze_partial_tokens apply to fungible assets only, and fail with UnexpectedNonFungibleToken otherwise. set_holder_frozen applies to NFT collections as well, and pallet-nft enforces it on transfer.
set_frozen_tokens sets the frozen balance absolutely; freeze_partial_tokens and unfreeze_partial_tokens adjust it relatively. See Asset Freezing.
Note the argument order differs between set_holder_frozen (holder first) and the other four (asset id first).
Events
| Event | Fields |
|---|---|
FrozenBalanceSet | caller_did: IdentityId, asset_holder: AssetHolder, asset_id: AssetId, frozen_balance: Balance |
SetAccountFreeze | caller_did: IdentityId, holder: AssetHolder, asset_id: AssetId, freeze: bool |
ControllerTransferTo | caller_did: IdentityId, asset_id: AssetId, source: AssetHolder, destination: AssetHolder, amount: Balance |
FrozenBalanceSet always carries the resulting absolute frozen balance, whichever call produced it.
Errors
| Error | Raised when |
|---|---|
InvalidTransferSenderIsFrozen | The sending holder is frozen for this asset |
ReceiverAffirmationRequired | The destination requires receiver affirmation, so a controller transfer cannot deliver into it |
InsufficientFrozenBalance | unfreeze_partial_tokens was asked to release more than is frozen |
FreezePartialTokenMustNotExceedHoldersBalance | freeze_partial_tokens would freeze more than the holder holds |
InsufficientBalance is unchanged but now accounts for frozen tokens: a holder's available balance is balance − locked − frozen.
Storage
| Item | Shape |
|---|---|
FrozenBalance | (AccountId32, AssetId) → Balance |
FrozenAccounts | (AccountId32, AssetId) → bool |
These cover account holders. Portfolio holders are stored in Portfolio.
Nft
Calls
| Index | Call | Arguments |
|---|---|---|
| 5 | approve | asset_id: AssetId, nft_id: NFTId, spender: Option<AccountId> |
| 6 | set_approval_for_all | asset_id: AssetId, operator: AccountId, approved: bool |
| 7 | controller_transfer_to | nfts: NFTs, source: AssetHolder, destination: AssetHolder |
approve with spender: None clears the approval. Only the account key holding the NFT, or an approved collection operator, may call it.
controller_transfer_to requires the caller to be an external agent of the collection. Unlike Asset::controller_transfer_to, it emits no dedicated event: like Nft::controller_transfer it reports through the existing NFTHoldingsUpdated, whose HoldingsUpdateReason is ControllerTransfer and whose source and destination holders are both carried in the event.
Events
| Event | Fields |
|---|---|
NFTApproval | owner: AccountId32, spender: Option<AccountId32>, asset_id: AssetId, nft_id: NFTId |
NFTApprovalForAll | owner: AccountId32, operator: AccountId32, asset_id: AssetId, approved: bool |
NFTApprovalSpent | owner: AccountId32, spender: AccountId32, asset_id: AssetId, nft_id: NFTId |
In all three, owner is the account key holding the NFT, not necessarily the caller — an operator may set or spend an approval on the holder's behalf, and the event still reports the holder.
No event is emitted when a per-token approval is implicitly cleared by a transfer.
Errors
| Error | Raised when |
|---|---|
NFTApprovalNotAuthorized | The caller neither holds the NFT nor operates the collection for its holder |
InsufficientNFTApproval | A spender attempted a transfer without an approval for that NFT |
ReceiverAffirmationRequired | The destination requires receiver affirmation, so a controller transfer cannot deliver into it |
Storage
| Item | Shape |
|---|---|
NFTAccountCount | (AccountId32, AssetId) → NFTCount |
TokenApproval | (AssetId, NFTId) → Option<AccountId32> |
OperatorApproval | (AccountId32 owner, AccountId32 operator, AssetId) → bool |
Storage version 7 → 8; NFTAccountCount is backfilled by migration.
Portfolio
Errors
| Error | Raised when |
|---|---|
PortfolioIsFrozen | The portfolio is frozen for the asset being moved |
As of v8.1.2 both this error and the pre-existing InsufficientPortfolioBalance are raised from ensure_sufficient_balance, rather than only from the multi-asset move path. InsufficientPortfolioBalance now measures balance − locked − frozen, so a partially frozen portfolio hits it where it previously did not.
ensure_sufficient_balance is not specific to portfolio moves. It backs three calls, and all three now refuse a frozen portfolio and measure its balance net of frozen tokens:
| Call | What it checks |
|---|---|
Portfolio::move_portfolio_funds | The sending portfolio can release each amount moved |
Sto::create_fundraiser | The offering portfolio can lock the full amount offered across tiers |
CapitalDistribution::distribute | The source portfolio can lock the full distribution amount |
Storage
| Item | Shape |
|---|---|
PortfolioNFTCount | (PortfolioId, AssetId) → NFTCount |
PortfolioFrozenAssets | (PortfolioId, AssetId) → Balance |
FrozenPortfolios | (PortfolioId, AssetId) → bool |
PortfolioFrozenAssets and FrozenPortfolios are the portfolio counterparts of Asset::FrozenBalance and Asset::FrozenAccounts.
Storage version 4 → 5; PortfolioNFTCount is backfilled by migration.
Settlement
Errors
| Change | Detail |
|---|---|
| Renamed | AllowancesNotSupportedForNFTs → DeprecatedAllowancesNotSupportedForNFTs |
The variant was renamed rather than deleted so that the indices of the errors after it are unchanged. It is no longer raised: NFT spender transfers now fail with Nft::InsufficientNFTApproval. Decoders keyed on error index are unaffected; decoders keyed on name need updating.
Behaviour changes
transfer_funds — two changes, neither altering the call signature:
- With
from = Some(holder)and a caller other than the holder, non-fungible funds are now accepted, consuming an NFT approval. Previously this combination was rejected. - A redundant custody check was removed: an instruction where the caller is the receiver but does not have custody of the receiving portfolio is now allowed.
Sto
Errors
| Error | Raised when |
|---|---|
InstructionNotSettled | invest created an instruction that did not reach InstructionStatus::Success within the call |
Added in v8.1.2 at the end of the variant list, so the indices of existing Sto errors are unchanged. The cause is a mandatory mediator on either asset in the instruction — the offering asset, or the raising asset when the investment is funded on chain — since the instruction cannot settle without that mediator's separate affirmation. See What changed in v8.1.2.
Behaviour changes without a signature change
These calls keep their index, arguments and encoding. Clients need no regeneration for them, but their outcome or cost differs.
| Call | Change in v8.1.2 |
|---|---|
MultiSig::create_multisig | Custom permissions are validated against the standard length and complexity limits. Weight includes that validation when permissions are supplied. |
Portfolio::quit_portfolio_custody | Runs the secondary-key portfolio permission check in addition to the custodian check. |
ExternalAgents::create_group, set_group_permissions | A nested Except extrinsic restriction is refused with Identity::ExceptNotAllowedForExtrinsics. The outer form was already refused with ExternalAgents::ExceptPermissionsNotAllowed. |
Sto::invest | Verifies its instruction settled; see above. |
Portfolio::move_portfolio_funds | Enforces the frozen balance, not only a whole-portfolio freeze. |
Nft::redeem_nft | No behavioural change: number_of_keys is still validated and Nft::NumberOfKeysIsLessThanExpected is still raised. The count is now read from the collection's key set rather than from the drained metadata, and the call is re-benchmarked accordingly. |
No error variant, event or storage item was removed in v8.1.2.
Runtime APIs
| API | Version | Change |
|---|---|---|
NFTApi | 3 → 4 | Added token_approval(asset_id, nft_id) → Option<AccountId> and operator_approval(owner, operator, asset_id) → bool |
Existing NFTApi methods are unchanged, and version 3 clients continue to work.
NFTApi::transfer_report and AssetApi::transfer_report keep their signatures but return more errors as of v8.1.2: both now evaluate the holder freeze and measure the available balance net of frozen tokens. A caller that treated an empty error list as "this transfer will succeed" gets a more accurate answer; no decoding change is required. See What changed in v8.1.2.
No custom JSON-RPC methods were added, removed or changed.