Overview
This minor release brings Confidential Assets (Polymesh DART) to Mainnet and upgrades them to the DART v1.0.0 protocol, with claim-based role gating, asset freezing, asset key updates, shared encryption keys and safer relayer fee payments. It also adds per-NFT freezes, makes the fungible and NFT precompiles ERC-7943 compliant, and fixes issues in MultiSig, identity authorizations, External Agents, settlement, committees and validators.
Runtime spec_version: 8_002_000
New Features
Confidential Assets (DART v1.0.0)
- The Confidential Assets pallet (index 70) is now available on Mainnet. The
ConfidentialAssetsAPI changes listed below are relative to Testnet (#2012) - Updated to the DART v1.0.0 protocol. Clients must generate proofs with DART v1.0.0; the proof types taken by
mediator_affirmation,submit_batched_proofs,relayer_submit_batched_proofsandexecute_instant_settlementhave changed (#2012) - Role gating:
set_required_claimandremove_required_claim(GC only) set or clear the claim required for theAssetCreator,AuditorandMediatorroles, trusting up toMaxTrustedClaimIssuers(2) issuers (#2012)- Only a live (unexpired) claim equal to the required one counts. It is checked at asset creation, on asset key updates and on key distribution
- Mediators use the auditor requirement when no mediator requirement is set
- An empty issuer list blocks the role, and removing the requirement makes the role permissionless
- Local development chains (
--dev,--chain testnet-dev) trust the first GC member to issueKnowYourCustomerclaims with the custom scopeDART:AssetCreator,DART:AuditororDART:Mediator
- Asset freezing: the asset issuer or the GC can freeze or unfreeze a confidential asset with
set_asset_frozen(#2012)- A frozen asset can't be used in new settlements or instant settlements (
AssetIsFrozen). Existing settlements, minting and key updates aren't affected - When a settlement hides the asset, the freeze takes effect once the asset tree roots from before the freeze expire (
MaxAssetCurveTreeRootAge, 24 hours) - The issuer can't lift or replace a freeze set by the GC (
AssetFrozenByRoot)
- A frozen asset can't be used in new settlements or instant settlements (
- Asset key updates: the asset issuer can replace an asset's auditor and mediator keys with
update_asset_keys, with the same checks as asset creation. Existing settlements keep the keys they were created with (#2012) - Shared encryption keys:
distribute_encryption_keyregisters a new encryption key to the caller and shares its secret with up toMaxSharedKeyRecipients(5) registered encryption keys. The shared key can be used as an asset auditor key, or as a mediator key by an account it was shared with. The caller and every recipient must meet the auditor requirement (#2012) - Relayer fee payments (
relayer_submit_batched_proofs) (#2012):- Every proof in a batch is bound to the batch's fee payment, so it can't be replayed with another payment
- A fee payment can only be claimed by the relayer it was made for, unless it is marked
is_broadcast - The payment must cover the transaction fee, plus at most
MaxRelayerCommission(10 POLYX) of relayer commission. Payments outside that range, or that reuse a spent fee nullifier, are rejected before they enter the transaction pool - The call must be submitted directly, not nested in another call (
RelayerCallMustBeTopLevel) - Fee account curve tree roots now expire after 4 hours instead of 2 days (
MaxFeeAccountCurveTreeRootAge) - New runtime API
ConfidentialAssetsApi::relayer_submit_batched_fee_inforeturns the weight and fee of arelayer_submit_batched_proofstransaction for a given batch, so clients can work out the fee payment amount
- Settlement proofs with more than
MaxSettlementLegs(10) legs are rejected (SettlementTooManyLegs), as are proof batches over their configured limit (TooManyProofs) (#2012) - Batched proofs that can finalize a settlement take an optional leg count, used to estimate the fee (
Nonemeans worst case). A wrong count fails withSettlementLegCountMismatch(#2012) - Rejected settlements are now finalized too. Finalized settlements are pruned, except for their final status, which is kept to prevent replays (#2012)
Per-NFT Freezes
- Asset agents can freeze individual NFTs for a holder (account key or portfolio) with
Nft::set_nfts_frozen(#2021) - A frozen NFT can't leave its holder: transfers, settlement affirmations and execution,
transfer_funds,move_portfolio_fundsand redemptions all fail until it is unfrozen - A freeze can be set before the holder receives the NFT, and applies once it arrives
- Controller transfers ignore freezes:
controller_transferandcontroller_transfer_tounfreeze the NFTs they take and emitNFTsFrozenStatusUpdatedwithfrozen: false - NFT transfer reports, including settlement transfer reports, now return every failure that applies (not owned, locked or frozen) instead of only the first, and report frozen NFTs even when settlement locks are skipped
ERC-7943 Compliant Precompiles
- Fungible asset precompile: new
supportsInterface(bytes4), which returnstrueforIERC165(0x01ffc9a7),IERC20(0x36372b07) andIERC7943Fungible(0x3edbb4c4) (#2030) - NFT precompile: new
setFrozenTokens(address,uint256,bool)andgetFrozenTokens(address,uint256), andsupportsInterfacenow also returnstrueforIERC7943NonFungible(0xbf1ef5fe) (#2021) - Both precompiles now emit the events ERC-7943 requires for forced transfers and frozen tokens (see Modified Events). The
FungibleAssetStubandNonFungibleAssetStubinterfaces are updated to match (#2021, #2030)
New Events
nft.NFTsFrozenStatusUpdated { caller_did, holder, nfts, frozen }: emitted byset_nfts_frozen, and withfrozen: falsewhen a controller transfer unfreezes NFTs (#2021)confidentialAssets.RequiredClaimSet { role, claim, trusted_issuers }andconfidentialAssets.RequiredClaimRemoved { role }(#2012)confidentialAssets.EncryptionKeyDistributed { caller_did, encryption_key, proof }(#2012)confidentialAssets.AssetFrozen { asset_id, freeze_origin }andconfidentialAssets.AssetUnfrozen { asset_id, unfreeze_origin }(#2012)- NFT precompile:
Frozen(address indexed account, uint256 indexed tokenId, bool indexed frozenStatus)(#2021)
Modified Events
Fungible Asset Precompile
forcedTransfernow emitsTransfer, thenForcedTransfer. If frozen tokens had to be unfrozen to cover the amount,TokensUnfrozenandFrozenare emitted first (#2030)setFrozenTokensalso emitsTokensFrozenorTokensUnfrozenwith the difference beforeFrozen, when the frozen amount changes.Frozenis still emitted on every call (#2030)freezePartialTokensandunfreezePartialTokensalso emitFrozenwith the new frozen total (#2030)
NFT Precompile
forcedTransfernow emitsTransferbeforeForcedTransfer(the order was reversed). If the token was frozen,Frozen(from, tokenId, false)is emitted first (#2021)
Confidential Assets
AssetStateLeafUpdatedis now emitted on every asset leaf update, including key updates and freeze changes (#2012)
New Errors
MultiSig::DuplicateSigners(#2027)ExternalAgents::StaleAuthorization(#2027)Settlement::InstructionHasNoLegs(#2027)Nft::InvalidNFTTransferNFTIsFrozen(#2021)Nft::NFTIsFrozen(#2021)Portfolio::InvalidTransferNFTIsFrozen(#2021)ConfidentialAssets:MissingLegMediators,EncryptionKeyMismatch,MissingRequiredClaim,NoKeyRecipients,TooManySharedKeyRecipients,EncryptionKeyNotShared,AssetIsFrozen,AssetFrozenByRoot,AssetIdOverflow,TooManyProofs,RelayerCallMustBeTopLevel,SettlementLegCountMismatch(#2012)
Removed Errors
ConfidentialAssets::InsufficientFeePaymentAmount: the fee amount is now checked by theCheckRelayerSubmitBatchedProofstransaction extension. On Testnet, the indices of all laterConfidentialAssetserrors shift down by one (#2012)
New Constants
ConfidentialAssets::MaxRelayerCommission= 10 POLYX (#2012)ConfidentialAssets::MaxTrustedClaimIssuers= 2 (#2012)ConfidentialAssets::MaxSharedKeyRecipients= 5 (#2012)
Modified Constants
ConfidentialAssets::MaxFeeAccountCurveTreeRootAge: 2 days → 4 hours (#2012)
Storage Changes
Nft: newFrozenNFTmap ((AssetId, AssetHolder, NFTId) → bool) (#2021)ExternalAgents: newAgentAuthCutoffmap ((AssetId, IdentityId) → u64), holding the latest authorization ID at the time an agent was removed (#2027)Validators: newIdentityValidatorStashesmap ((IdentityId, AccountId) → ()) of each identity's validating stashes. The storage version goes from 1 to 2 (#2027)ConfidentialAssets: newRequiredClaims,AssetFrozen,SharedKeyRecipients,LegMediators,CachedDartParametersVersionandRelayerSubmitExtensionMarker.Keysnow uses the DART v1AssetKeysformat, andFeeAccountRegistrationsis removed. The storage version goes from 0 to 1 (#2012, #2031)
Data Migration
ConfidentialAssetsstorage version 0 → 1 (#2012):- Installs a blocking claim requirement for every gated role, until the GC replaces it
- Rejects all pending confidential settlements, and finalizes rejected settlements with nothing left to finalize
- Converts existing asset keys to the DART v1 format and recommits each asset's leaf in the asset curve tree
ConfidentialAssets: the cached DART parameters are regenerated when the DART protocol version changes (#2031)Validatorsstorage version 1 → 2: fillsIdentityValidatorStashesfrom the current validators (#2027)
Bug Fixes
MultiSig
create_multisig,add_multisig_signersandadd_multisig_signers_via_adminreject duplicate signers (DuplicateSigners) (#2027)- Removing a signer now invalidates the key's outstanding authorizations, so a pending invitation can't be used to rejoin the MultiSig (#2027)
Identity
- Outdated authorizations, such as those left by a removed secondary key or MultiSig signer, can now be removed with
Identity::remove_authorization(#2027) - Transactions that would charge an authorization's issuer for accepting or removing an outdated authorization are now rejected before execution. Outdated authorizations can still be removed with
auth_issuer_pays: false(#2027)
External Agents
- A
BecomeAgentauthorization issued before an agent was removed can no longer be accepted (StaleAuthorization) (#2027)
Settlement
- Instructions without legs are rejected (
InstructionHasNoLegs) (#2027) - Pruning an instruction now also removes its memo (#2027)
- When an affirmation's holder set contains both the sender and the receiver of a leg, the leg is now counted for both. This changes the result of
get_affirmation_countand the counts required byaffirm_instruction_with_countandaffirm_with_receipts_with_count(#2027)
Asset
- Asset metadata can no longer be locked with an empty value.
set_asset_metadata,register_and_set_local_asset_metadataandset_asset_metadata_detailsfail withAssetMetadataValueIsEmpty(#2027)
Portfolio and NFT
- Accepting a portfolio custody authorization fails if the portfolio no longer exists (
PortfolioDoesNotExist) (#2027) - NFT transfers to a portfolio that doesn't exist are rejected, and shown in the NFT transfer report (#2027)
Precompiles
- ERC-3643
setSymbolnow works for an asset that already has a ticker. It registers the new ticker, releases the previous one (which the caller's identity must own) and links the new one. Setting the current symbol again does nothing (#2027) - The NFT precompile's
canTransfernow returnstruefor transfers between keys of the same identity thattransferFromallows (#2027)
Relayer
- A subsidised key can now always pay for its own Relayer calls, such as
remove_subsidy. Before, these were rejected if the subsidy's remaining POLYX didn't cover the fee (#2027)
Committees and Groups
- A committee motion now needs at least one vote to pass or be rejected, even if the committee has no seats or a zero threshold (#2027)
- When members leave a committee, the votes of all outgoing members are removed from open motions. Before, only the first outgoing member's vote was removed (#2027)
MemberRemovedevents emitted while removing expired inactive members now name the removed member instead of the member being disabled (#2027)
Validators
Validators::remove_permissioned_validatornow also chills every stash of the identity that is still validating (#2027)
Weight Changes
Asset::redeem,controller_transferandcontroller_transfer_tonow include the worst-case cost of updating asset statistics, and refund the unused part (#2027)CapitalDistribution::claimandpush_benefitnow include the worst-case cost of the asset's transfer checks, and refund the unused part (#2027)Validators::remove_permissioned_validatorcharges for the worst-case number of stashes, and refunds down to the number it chilled (#2027)- Regenerated weights for the asset, capital distribution, compliance manager, confidential assets, external agents, identity, MultiSig, NFT, PIPs, portfolio, relayer, settlement, STO and validators pallets (#2021, #2027, #2033)
Other Changes
- New
WorkerModulespallet (index 60) that lets the GC upgrade the Polymesh Worker's DART proof-verification modules on-chain, without a node release. It is only callable by the GC and isn't for regular users (#1964) - On x86_64 and ARM64 Linux, the node now runs native DART worker modules in separate worker processes (re-executions of the
polymeshbinary). If a worker process fails, the proof is verified in the runtime instead (#2012)
Full Changelog: v8.1.3...v8.2.0