Add canSend, canReceive, setFrozenTokens, getFrozenTokens - #1990
Add canSend, canReceive, setFrozenTokens, getFrozenTokens#1990HenriqueNogara wants to merge 10 commits into
Conversation
There was a problem hiding this comment.
Pull request overview
Adds ERC-7943-style capabilities to the fungible asset EVM precompile, including compliance-side “can send/receive” checks and per-holder frozen-token tracking, with the necessary runtime plumbing (storage, extrinsic, compliance hook) and weights/benchmarks.
Changes:
- Extend the fungible asset precompile interface with
canSend,canReceive,setFrozenTokens, andgetFrozenTokens(plusFrozenevent). - Add frozen-balance tracking for both accounts and portfolios, and enforce frozen amounts in balance-availability checks.
- Add compliance helper
is_holder_compliantand corresponding weights/benchmarks for the new API paths.
Reviewed changes
Copilot reviewed 9 out of 10 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| primitives/src/traits.rs | Extends compliance trait with is_holder_compliant for sender/receiver-side checks. |
| precompiles/src/interfaces/FungibleAssetStub.sol | Updates Solidity interface/stub with new ERC-7943 functions/events. |
| pallets/weights/src/pallet_asset.rs | Adds weight functions for freezing, frozen-balance reads, and holder compliance checks. |
| pallets/precompiles/src/interface/mod.rs | Routes new IFungibleAsset calls and enforces read-only restrictions for setFrozenTokens. |
| pallets/precompiles/src/interface/erc7943.rs | Implements the new precompile entrypoints (freeze/getFrozenTokens/canSend/canReceive) with gas adjustment. |
| pallets/portfolio/src/lib.rs | Adds storage + helpers to track frozen balances at the portfolio level. |
| pallets/compliance-manager/src/lib.rs | Implements is_holder_compliant for side-specific compliance evaluation. |
| pallets/asset/src/lib.rs | Adds frozen-balance storage/extrinsic, updates balance checks to account for frozen amounts, and exposes holder-level compliance helper. |
| pallets/asset/src/benchmarking.rs | Adds benchmarks for the new weights and holder compliance paths. |
Suppressed comments (1)
pallets/asset/src/lib.rs:2972
- This helper’s doc comment says it applies to an account, but
asset_holdercan also be a portfolio. Consider updating the wording to avoid misleading future readers.
/// Sets the frozen transfer amount for an account on a given asset.
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 12 out of 13 changed files in this pull request and generated 1 comment.
Suppressed comments (3)
pallets/asset/src/lib.rs:3446
skip_locked_checknow also implicitly skips frozen balance checks, because it bypassesensure_sufficient_balance(which now accounts for frozen tokens). This can makeasset_transfer_reportincorrectly report that a transfer is possible even when the sender has insufficient unfrozen balance.
if Self::get_holders_balance(sender, asset_id) < transfer_value {
asset_transfer_errors.push(Error::<T>::InsufficientBalance.into());
}
} else {
if let Err(e) = Self::ensure_sufficient_balance(sender, asset_id, transfer_value, false)
pallets/portfolio/src/lib.rs:335
- New
PortfolioFrozenAssetsentries are not cleared indelete_portfolio(which currently removesPortfolioAssetBalances/PortfolioLockedAssetsprefixes). SincesetFrozenTokenscan set an amount greater than the portfolio’s balance, a portfolio can be “empty” but still have frozen entries, leaving stale state that could affect a later re-creation of the samePortfolioId. Consider clearingPortfolioFrozenAssets(and/or asserting it is empty) during deletion.
/// Amount of assets frozen in a portfolio.
#[pallet::storage]
pub type PortfolioFrozenAssets<T: Config> = StorageDoubleMap<
_,
Twox64Concat,
PortfolioId,
Blake2_128Concat,
AssetId,
Balance,
ValueQuery,
>;
pallets/asset/src/lib.rs:3771
ensure_sufficient_balancenow performs an additional storage read (FrozenBalance/PortfolioFrozenAssets) for non-controller transfers. Any dispatchables/RPC-weighted paths that rely onensure_sufficient_balance(e.g.base_transfer,asset_transfer_report_*, burns, locking flows) will have increased DB reads and should have their benchmark-derived weights regenerated to avoid undercharging.
let frozen_balance = Self::get_holders_frozen_balance(holder, asset_id);
let unavailable_balance = locked_balance.saturating_add(frozen_balance);
current_balance.saturating_sub(unavailable_balance)
}
71f57d4 to
c8ba324
Compare
Neopallium
left a comment
There was a problem hiding this comment.
One small change needed.
| call: &IFungibleAsset::setFrozenTokensCall, | ||
| env: &mut impl Ext<T = T>, | ||
| ) -> Result<Vec<u8>, Error> { | ||
| env.charge(<T as pallet_asset::Config>::WeightInfo::set_frozen_tokens())?; |
There was a problem hiding this comment.
The call_runtime helper will do this. It can get the weight from the RuntimeCall enum.
changelog
new features
canSend, canReceive, setFrozenTokens, getFrozenTokensto the precompile interface