github PolymeshAssociation/Polymesh v8.2.0

pre-releaseone hour ago

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 ConfidentialAssets API 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_proofs and execute_instant_settlement have changed (#2012)
  • Role gating: set_required_claim and remove_required_claim (GC only) set or clear the claim required for the AssetCreator, Auditor and Mediator roles, trusting up to MaxTrustedClaimIssuers (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 issue KnowYourCustomer claims with the custom scope DART:AssetCreator, DART:Auditor or DART: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)
  • 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_key registers a new encryption key to the caller and shares its secret with up to MaxSharedKeyRecipients (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_info returns the weight and fee of a relayer_submit_batched_proofs transaction 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 (None means worst case). A wrong count fails with SettlementLegCountMismatch (#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_funds and 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_transfer and controller_transfer_to unfreeze the NFTs they take and emit NFTsFrozenStatusUpdated with frozen: 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 returns true for IERC165 (0x01ffc9a7), IERC20 (0x36372b07) and IERC7943Fungible (0x3edbb4c4) (#2030)
  • NFT precompile: new setFrozenTokens(address,uint256,bool) and getFrozenTokens(address,uint256), and supportsInterface now also returns true for IERC7943NonFungible (0xbf1ef5fe) (#2021)
  • Both precompiles now emit the events ERC-7943 requires for forced transfers and frozen tokens (see Modified Events). The FungibleAssetStub and NonFungibleAssetStub interfaces are updated to match (#2021, #2030)

New Events

  • nft.NFTsFrozenStatusUpdated { caller_did, holder, nfts, frozen }: emitted by set_nfts_frozen, and with frozen: false when a controller transfer unfreezes NFTs (#2021)
  • confidentialAssets.RequiredClaimSet { role, claim, trusted_issuers } and confidentialAssets.RequiredClaimRemoved { role } (#2012)
  • confidentialAssets.EncryptionKeyDistributed { caller_did, encryption_key, proof } (#2012)
  • confidentialAssets.AssetFrozen { asset_id, freeze_origin } and confidentialAssets.AssetUnfrozen { asset_id, unfreeze_origin } (#2012)
  • NFT precompile: Frozen(address indexed account, uint256 indexed tokenId, bool indexed frozenStatus) (#2021)

Modified Events

Fungible Asset Precompile

  • forcedTransfer now emits Transfer, then ForcedTransfer. If frozen tokens had to be unfrozen to cover the amount, TokensUnfrozen and Frozen are emitted first (#2030)
  • setFrozenTokens also emits TokensFrozen or TokensUnfrozen with the difference before Frozen, when the frozen amount changes. Frozen is still emitted on every call (#2030)
  • freezePartialTokens and unfreezePartialTokens also emit Frozen with the new frozen total (#2030)

NFT Precompile

  • forcedTransfer now emits Transfer before ForcedTransfer (the order was reversed). If the token was frozen, Frozen(from, tokenId, false) is emitted first (#2021)

Confidential Assets

  • AssetStateLeafUpdated is 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 the CheckRelayerSubmitBatchedProofs transaction extension. On Testnet, the indices of all later ConfidentialAssets errors 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: new FrozenNFT map ((AssetId, AssetHolder, NFTId) → bool) (#2021)
  • ExternalAgents: new AgentAuthCutoff map ((AssetId, IdentityId) → u64), holding the latest authorization ID at the time an agent was removed (#2027)
  • Validators: new IdentityValidatorStashes map ((IdentityId, AccountId) → ()) of each identity's validating stashes. The storage version goes from 1 to 2 (#2027)
  • ConfidentialAssets: new RequiredClaims, AssetFrozen, SharedKeyRecipients, LegMediators, CachedDartParametersVersion and RelayerSubmitExtensionMarker. Keys now uses the DART v1 AssetKeys format, and FeeAccountRegistrations is removed. The storage version goes from 0 to 1 (#2012, #2031)

Data Migration

  • ConfidentialAssets storage 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)
  • Validators storage version 1 → 2: fills IdentityValidatorStashes from the current validators (#2027)

Bug Fixes

MultiSig

  • create_multisig, add_multisig_signers and add_multisig_signers_via_admin reject 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 BecomeAgent authorization 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_count and the counts required by affirm_instruction_with_count and affirm_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_metadata and set_asset_metadata_details fail with AssetMetadataValueIsEmpty (#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 setSymbol now 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 canTransfer now returns true for transfers between keys of the same identity that transferFrom allows (#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)
  • MemberRemoved events emitted while removing expired inactive members now name the removed member instead of the member being disabled (#2027)

Validators

  • Validators::remove_permissioned_validator now also chills every stash of the identity that is still validating (#2027)

Weight Changes

  • Asset::redeem, controller_transfer and controller_transfer_to now include the worst-case cost of updating asset statistics, and refund the unused part (#2027)
  • CapitalDistribution::claim and push_benefit now include the worst-case cost of the asset's transfer checks, and refund the unused part (#2027)
  • Validators::remove_permissioned_validator charges 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 WorkerModules pallet (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 polymesh binary). If a worker process fails, the proof is verified in the runtime instead (#2012)

Full Changelog: v8.1.3...v8.2.0

Don't miss a new Polymesh release

NewReleases is sending notifications on new releases.