I think the change in the even signature makes sense indeed. Will include it or fell free to open a PR for it. Thanks!
Hi everyone! Just updated the PR incorporating @xalerās feedback and @mihaic195ās suggestion for the ForcedTransfer event signature.
Renaming
I believe aligning function names with existing standards like ERC-3643 is beneficial, even with different argument signatures. The key value is establishing shared semantics across RWA implementations. For example, when developers (even users) see setFrozenTokens, they can expect consistent behavior regardless of the underlying token standard.
Users have shown to care little about the underlying specification, so itād be beneficial to avoid confusing them.
@ernestognw, my point from previous comments stands.
Just clarifying, are you suggesting we standardize pause functionality in a separate ERC?
Iām not convinced this warrants its own standard given the widespread adoption of OpenZeppelinās pausable pattern (paused(), pause(), unpause()). I would argue it can be considered standard already.
For ERC-7943, we could simply specify that isUserAllowed and canTransfer SHOULD return false when paused() returns true. This acknowledges the existing de facto standard without over-engineering. Thoughts?
Proposal: Token-Type-Specific Interfaces
The discussion has highlighted that we prioritize implementation coordination (hence the ERC-3643 naming alignment), while the biggest concern is that the differences in the argument list disallow real backwards compatibility even if the name matches.
Iāve been thinking that most of these differences (e.g. like the getFrozenTokens lack of sense in ERC-721) could be alleviated if we recognize three functional token variants and provide specific interfaces for each: 1) fungible, 2) non fungible and 3) multitoken.
I think these 3 categories are exhaustive enough to still consider the ERC to aim for universality. The specific interface for each would be:
interface IFungibleRWA is IERC165 {
event ForcedTransfer(address indexed from, address indexed to, uint256 amount);
event Frozen(address indexed user, uint256 amount);
error ERC7943NotAllowedUser(address account);
error ERC7943InsufficientUnfrozenBalance(address user, uint256 amount, uint256 unfrozen);
function forcedTransfer(address from, address to, uint256 amount) external;
function setFrozenTokens(address user, uint256 amount) external;
function getFrozenTokens(address user) external view returns (uint256 amount);
function canTransfer(address from, address to, uint256 amount) external view returns (bool allowed);
function isUserAllowed(address user) external view returns (bool allowed);
}
interface INonFungibleRWA is IERC165 {
event ForcedTransfer(address indexed from, address indexed to, uint256 indexed tokenId);
event Frozen(address indexed user, uint256 indexed tokenId);
error ERC7943NotAllowedUser(address account);
error ERC7943InsufficientUnfrozenBalance(address user, uint256 tokenId);
function forcedTransfer(address from, address to, uint256 tokenId) external;
function setFrozenTokens(address user, uint256 tokenId) external;
function canTransfer(address from, address to, uint256 tokenId) external view returns (bool allowed);
function isUserAllowed(address user) external view returns (bool allowed);
}
interface IMultiRWA is IERC165 {
event ForcedTransfer(address indexed from, address indexed to, uint256 indexed tokenId, uint256 amount);
event Frozen(address indexed user, uint256 indexed tokenId, uint256 amount);
error ERC7943NotAllowedUser(address account);
error ERC7943InsufficientUnfrozenBalance(address user, uint256 tokenId, uint256 amount, uint256 unfrozen);
function forcedTransfer(address from, address to, uint256 tokenId, uint256 amount) external;
function setFrozenTokens(address user, uint256 tokenId, uint256 amount) external;
function getFrozenTokens(address user, uint256 tokenId) external view returns (uint256 amount);
function canTransfer(address from, address to, uint256 tokenId, uint256 amount) external view returns (bool allowed);
function isUserAllowed(address user) external view returns (bool allowed);
}
This approach maintains the āminimal universal interfaceā goal while providing type-specific clarity. Each interface would use appropriate parameter sets and event signatures for its token type, eliminating the current awkwardness of unused parameters.
This categorization reflects how RWA tokens actually behave in practice (e.g. now it does match ERC-3643 interface) while preserving the standardās minimality.
What are your thoughts on this direction?
i just starting to learn the erc standards about RWA. I am pretty agree that we need a standard interface for RWA token like 7943. I also like the modular compliance design from 3643. If i am launching my own RWA token and EIP 7943 get approved, i will use 7943ās interface and in behind use compliance modules to implement the interfaces. Any thoughts about this?
Hi everyone! Iām fully aligned with the idea of type-specific interfaces (fungible / non-fungible / multi). That maps to how things are actually built and removes the awkward āone signature fits allā problem.
Where Iād still urge a course-correction is scope. If 7943 is to be āuniversal,ā the biggest win is for integrators (wallets, custodians, venues, DeFi adapters) to have one predictable read layer that answers three questions:
- Will this pass? (pre-flight)
- If not, why not? (a small shared reason-code space)
- What can the user do to fix it? (optional machine-readable details)
Concretely, I propose keeping admin/write methods (freeze, forced transfer, pause, etc.) out of the minimal surface and standardizing a tiny uRWA-View per token type. That way ERC-3643 / ERC-1400 / 7518 / 7551 (and others) can all implement this without clashing with their own admin ABIs.
Minimal uRWA-View (example for fungible)
interface IFungibleRWAView {
// 1) Exact amount user can move right now (excludes frozen/blocked/etc.).
function uRWATransferableBalance(address user) external view returns (uint256);
// 2) User eligibility pre-check. data = optional context (attestations, zk proofs, metadataā¦)
// reasonCode: 0 = OK; small shared range for common reasons; >=1024 vendor/issuer-specific.
function uRWAUserCheck(address user, bytes calldata data)
external view returns (bool ok, uint256 reasonCode);
// 3) Transfer pre-check (would this pass *now*?). Same reason semantics as above.
function uRWATransferCheck(
address from,
address to,
uint256 amount,
bytes calldata data
) external view returns (bool ok, uint256 reasonCode);
}
Optional (separate interface ID) Details facet for richer UX/debug:
interface IFungibleRWADetails {
// schema describes how to decode `details`
function uRWAUserDetails(address user, bytes calldata data)
external view returns (bytes32 schema, bytes memory details);
function uRWATransferDetails(
address from, address to, uint256 amount, bytes calldata data
) external view returns (bytes32 schema, bytes memory details);
}
The same pattern applies to non-fungible and multi-token views (with tokenId and amount as appropriate). This gives integrators one clean pre-flight + reason path across all RWA implementations while letting each standard keep its established admin semantics and events.
On naming alignment & pausability
- Iām fine to align with 3643 where it helps (e.g.,
canTransfersemantics), but putting that logic behind a neutraluRWA*view avoids collisions and expectations mismatches. Users donāt care which spec is under the hood and integrators care about predictability. - Pausable: totally agree to not define it on this ERC and treat it as reason code (e.g., reasonCode 42 =
ASSET_PAUSED) and/or havecanTransfer/uRWATransferCheckreturn false when paused.
On setFrozenTokens vs partial freeze
Iām not convinced setFrozenTokens(address user, uint256 amount) (absolute setter) is the best primitive. In ERC-3643 we expose delta-based ops (freezePartialTokens, unfreezePartialTokens), which are:
- Safer for concurrency/atomicity,
- Clearer for auditability (explicit intent to +/- frozen balance),
- More flexible for court-ordered or programmatic adjustments.
If you really want a single admin knob, an implementation can derive delta ops from an absolute ātarget,ā but Iād caution against baking an absolute setter into a universal surface, especially if we agree that universal 7943 should primarily standardize read paths for integrators. Admin flavors can live in optional facets or the underlying standard (3643/1400/ā¦).
How we can help
This āintegrator-firstā piece is missing in ERC-3643 today. If we converge on a minimal uRWA-View, Iām happy to implement and ship an ERC-3643 adapter so 3643 tokens āspeak uRWAā out of the box (pre-check, reason codes, optional details). Same can be done for ERC-1400.
If youāre open, please have a look at the IERC7943 proposal i made above(not perfect for sure, to be refined). It keeps 7943 universal, avoids yet-another admin interface, and gives integrators exactly what they need: one pre-flight, one reason table, optional details as well as consistently across fungible / NFT / multi-token RWAs. Note that the proposal above was still mixing the 3 types of tokens but i agree we can separate them as you proposed.
Pausability
I can see it happening both ways, I donāt have a strong opinion about it.
If we aim for the ERC-7943 to be a functional RWA token for 95% of the issuers out of the box, Iād say it makes sense to standardize it here.
If not, and the objective is to have a minimal interface from which to build functionality, I think it should remain outside of the ERC.
Regarding whether pausability deserves its own standard or extension, I completely agree in that OZās is the de-facto standard for pausability in the industry, but I do see important fragmentation in the current leading RWA issuers see previous post.
Token-type specific interfaces
Onboard with different interfaces for ERC20, ERC721, and ERC1155.
Thereās obviously value in having all token implementations share the same interface and the standard token-agnostic, but also many trade-offs arise when trying to achieve compatibility and minimize confusion.
Features vs minimal interface
@xaler, @ernestognw, @Joachim-Lebrun
If the decision is taken to set the scope of the ERC to a minimal interface, and move features to the implementation layer, which I believe aligns with the view-only vision, Iād say itās worth to revisit whether the standard should or should not include token freezing.
Referring to my first comment, to me, this ERC is either:
- A minimal transfer checking interface, which can include user and transferrable balance checking as well.
- A baseline RWA token that fits 90-95% of use-cases: freezing/blocking, maybe pausing, but no allowlisting (very customizable).
I see value in both, but much more on having a slightly opinionated standard.
I believe this is the most important topic to agree upon. A potential solution would be to break this ERC into two.
Hi @tinom9
I think the focus should be on the āminimal interfaceā direction. To reconcile the need for common features (pause, freeze/block, allowlist, missing on-chain identity/claims, jurisdiction limits, period limits, etc.) without imposing any single admin model (3643/1400/ā¦) :
- Put those concepts in the read-only layer as standardized reason codes, not as write/admin functions.
- Leave admin mechanics (how to pause/freeze/allowlist/identity) to each underlying standard or implementation.
This gives wallets/custodians/venues one predictable flow:
- Pre-flight ā
uRWATransferCheck(..) ā (ok, reason) - Why blocked ā
reasonfrom a small shared table (e.g.,PAUSED,FROZEN_BALANCE,USER_NOT_ELIGIBLE,MISSING_IDENTITY,MISSING_CLAIM,ALLOWLIST_REQUIRED,JURISDICTION_BLOCK,LIMIT_EXCEEDED, etc.;>=1024vendor-specific). Can discuss if it should be an array here as it could be several reasons at once. - (Optional) How to fix ā a separate
uRWATransferDetails(..) ā (schema, details)facet for machine-readable guidance, where privacy-sensitive implementations can return minimal info.
This approach standardizes the existence of these features at the UX layer while preserving freedom at the admin layer (no new āforce/freeze/pauseā verbs that collide with 3643/1400 or OZ Pausable).
Token-type specific vs one-size-fits-all: Iām fine either way. Three type-specific view interfaces (20/721/1155) reduce ambiguity; a single polymorphic view keeps ABIs smaller. In both cases integrators will add new checks, so Iāll support whichever the group prefers as long as the reason-code surface is shared.
Practical proposal
- Standardize a tiny uRWA-View per chosen shape (type-specific or unified):
transferableBalance,userCheck(user,data) ā (ok,reason),transferCheck(from,to,amount,tokenId?,data) ā (ok,reason). - Publish a reserved reason-code table, keep it short, leave room for vendor codes.
- Make the Details facet optional (separate ERC-165 ID).
- Specify that when an implementation is paused (via any mechanism, including OZ Pausable),
transferCheckSHOULD returnok=falsewithreason=PAUSED.
If we converge on this, Iām happy to implement it for ERC-3643 so 3643 tokens expose the uRWA-View immediately. Same can be done for ERC-1400. This delivers real utility to integrators now, while allowing opinionated admin features to evolve independently.
ps : i also donāt have a strong opinion on the namespaced functions starting with uRWA but it would have the advantage of making it clear that these are the universal interfaces that should be called by integrators. On the other hand, some might find these a bit ugly, so i am fine either way
pps: if the collective decision is to still define some write/admin functions and related events, i would put them as optional (SHOULD/COULD not MUST) and define them on a separate interface (separate ERC-165 ID) to allow for flexibility on that side
Thanks everyone for the thoughtful feedback. A few updates and clarifications from my side:
Separation of Interfaces
I agree with the idea of separating different token types into their own interfaces. This will help keep things cleaner and more intuitive for implementers. Similarly, I also agree that admin functions should live in their own interface, but Iād like to keep them under the umbrella of ERC-7943 so that everything remains grouped in one standard rather than fragmenting across multiple EIPs. This way we can preserve modularity while also keeping discoverability and cohesion. I still believe that automated processes will benefit from having them. At the same time, this would allow for both of these:
- A minimal transfer checking interface, which can include user and transferrable balance checking as well.
- A baseline RWA token that fits 90-95% of use-cases: freezing/blocking, maybe pausing, but no allowlisting (very customizable).
canTransfer and Pausability
Good point about pausability. I agree that canTransfer should be able to return false if the contract is in a paused state and this can be defined in the EIP, acknowledging the existence of standardized pausability designs. Thatās consistent with how developers already think about transfer checks, and it avoids re-inventing a separate mechanism.
Return Values vs. Reverts
On the question of return values for explaining failure reasons: I still believe that custom errors are sufficient to provide clarity when a transaction or a call reverts. Theyāre gas-efficient, standard across Solidity, and expressive enough. Iād like to hear more from those who think additional return-based mechanisms are necessary, is there a concrete integration scenario where custom errors fall short? More context would help here.
About returning arbitrary data to the view functions Iād keep a generic bytes eventually and would leave out of the scope defining the schema and the error codes / reasons. I feel there are so diverse reasons + eventual suggested actions that it can be beneficial to leave it generic. Wdyt @Joachim-Lebrun ?
setFrozenTokens Absolute vs. Incremental
After discussing with @arr00 and revisiting the spec, I now agree that having setFrozenTokens as an absolute setter makes more sense. The current āSHOULD NOT allow freezing more than the held balanceā guidance, combined with the security note on front-running, actually incentivizes users to front-run freeze attempts in order to DOS the functionality.
While the situation resembles the old ERC-20 approve race condition, the incentives here are different: the motivation to avoid a freeze is much stronger than the motivation to manipulate allowances. That makes the theoretical risk more practical.
Therefore I plan to make the following change:
- Change the line from āSHOULD NOT allow freezing more assets than those heldā to a āSHOULD allow freezing more assets than those heldā (so freezing can also cover future balances).
- Keep the security considerations where I mention incremental deltas, since thatās still a valid implementation pattern some may want to explore.
This change should cover more use cases (e.g. freezing incoming funds) and simultaneously remove the denial-of-service vector. Still the function is front-runneable but at least the ddos attack vector is infeasible now.
I also recall @frangio once noted that increaseAllowance/decreaseAllowance ended up causing more problems than they solved, but I donāt remember the details. @ernestognw maybe you recall why? That context might help us avoid repeating the same mistakes here.
Hey team ![]()
Iāve opened a PR to address all the feedback above ā Update ERC-7943: [Update 7943] Split into separate interfaces by xaler5 Ā· Pull Request #1210 Ā· ethereum/ERCs Ā· GitHub
Main things I want to discuss and resolve are:
-
Now that interfaces are split, the
getFrozenTokensof the ERC-721 has a different signatures (it returns a bool), should we keep uint256 instead ? -
Now same errors have different signatures across different interfaces, should we keep the same naming or use more specific ones for each interface ?
-
I hope I didnāt miss anything but Iāve refactored the showed examples. Can any of you review putting particular attention to:
- Now one can freeze more than actual balance, this means that calculation of āunfrozenā balance changed, I hope I didnāt miss anything.
- I should have applied new interfaces correctly, but please give it a double or triple check
Looking forward to receive some feedback !
Thanks for putting it together @xaler! Adding some thoughts on the discussion points you shared:
- Now that interfaces are split, the
getFrozenTokensof the ERC-721 has a different signatures (it returns a bool), should we keep uint256 instead ?
I think the bool return type is correct and should be kept. This aligns perfectly with the semantic model of ERC-721 tokens where each token is either frozen or not, given thereās no partial freezing concept for unique tokens.
From the EVM perspective, both bool and uint256 are stored in 32-byte slots, so thereās no technical incompatibility. The semantic clarity is more valuable than maintaining identical signatures imo
- Now same errors have different signatures across different interfaces, should we keep the same naming or use more specific ones for each interface ?
Historically, OpenZeppelin has never recommended relying on custom errors for backwards compatibility, so I wouldnāt be too worried about having different errors per interface. The current approach follows the principle of error specificity of ERC-6093
I hope I didnāt miss anything but Iāve refactored the showed examples.
The updates look sound to me. The _unfrozenBalance function seems fine. Also the interfaces were applied correctly.
Hi Everyone! Bryn here from Hacken. Iām sharing below some design review points from our auditors, after an awesome private collaboration with @xaler this week. This doesnāt constitute a full design audit, but lays the groundwork for a thorough security assessment on the 7943 standard. Please feel free to leave your feedback:
Compliance Issues in EIP Specification
Missing Checks for msg.sender
Problem:
Many compliance rules within the EIP, particularly those governing token transfers and operations, currently depend solely on the from and to addresses. This approach overlooks the crucial role of the initiator or operator (msg.sender) in many real-world scenarios.
For instance, compliance checks often need to validate the identity and permissions of the entity initiating the transfer, not just the sender and receiver.
Example:
The specification states:
"The
canTransferMUST validate that the amount being transferred doesnāt exceed the unfrozen amount (which is the difference between the current balance and the frozen balance). Additionally it MUST perform anisUserAllowedcheck on thefromandtoparameters.ā
Elaboration:
While from and to are essential, the msg.sender (the account that directly invoked the function) is equally vital for comprehensive compliance.
Consider scenarios involving delegated transfers or third-party initiated operations. Without explicitly including msg.sender in isUserAllowed checks, an unauthorized operator could potentially bypass compliance rules by initiating transfers on behalf of allowed from or to addresses.
Recommendation:
It is strongly advised to explicitly state that msg.sender may also be validated for isUserAllowed to ensure a holistic approach to access control and compliance.
Redundant/Fragile Double Checks around _update
Problem:
The _update path in the examples exhibits redundant and potentially fragile logic by performing multiple checks for the same conditions.
Elaboration:
The current sequence is:
- An explicit balance check is performed.
- An unfrozen check is performed.
- Then,
require(canTransfer(...))is called.
The issue here is that canTransfer itself is designed to re-check policy conditions, including balance and unfrozen amounts. This results in checks being done twice.
Consequences:
- Increased Gas Costs: Duplicating checks leads to unnecessary computation and higher gas consumption for every transaction using
_update. - Risk of Drift: If the logic within
canTransferchanges (e.g., adding new compliance rules), the redundant checks in_updatemight not be updated in sync.- This can result in inconsistencies:
_updatemay pass its initial checks, butcanTransfercould still fail, or vice versa. - Such drift can introduce subtle bugs, unexpected behavior, and security vulnerabilities.
- This can result in inconsistencies:
Recommendation:
The design should be streamlined.
_updateshould rely directly oncanTransferfor all transferability validation.- Instead of duplicating the logic, simply call
canTransferto determine if the transfer is permissible.
Thanks all for the throughout discussion. Being currently reviewed under MICA, EMI and Payment Institution licences by the regulator I can see the usefulness of applying this standard to the RWA contracts.
My suggestions:
-
as mentioned above - to split ERC20 and other interfaces to avoid those tokenId. etc. It is common in other ERCs as well, e.g. narrow mint() related ERC.
-
as mentioned by @EdwinMata as minting example, I miss the
bytes calldata legalProofforforcedTransfer()andsetFrozenTokens()
I strongly advocate to extend these functions with it, to be comliant with those jurisdictions / regulators where the audit trail is / will be requested.
I.e. ā
function forcedTransfer(address from, address to, uint256 tokenId, uint256 amount, bytes calldata legalProof) external;
function setFrozenTokens(address user, uint256 tokenId, uint256 amount, bytes calldata legalProof) external;
bool return type in getFrozenTokens for ERC-721
Agreed. Since weāre having different interfaces, letās follow the most intuitive patterns for their respective token types.
Error signatures across interfaces
Weāre already having different function selectors. Integrators will have to know the nuances of each token type, so I donāt find this point problematic either.
msg.sender checks
I believe the spirit of canTransfer already allows for the extensibility that, among other use-cases, msg.sender checks require.
It may also rely on other circumstances that are not necessarily related to the function parameters (from, to, amount, and tokenId), such as pausability, or block.timestamp.
I think this is already well defined in the draft, but also that itād be positive to add msg.sender as another potential discriminator:
- MAY depend on context (e.g., current timestamp, `block.number`, or `msg.sender`).
Legal proof parameters
Should all operations that require a legal proof implement this parameter?
Potentially, and this is already required and implemented in RWA tokens Iāve developed, legal proof or authorization can be enforced in every token action.
I believe this responsibility should be transferred to the specific compliance implementation, and perform multi-call operations when needed to satisfy these requirements.
For example:
contract ComplianceOperator {
function setFrozenTokensWithProof(address _user, uint256 _tokenId, uint256 _amount, bytes calldata _legalProof) public {
legalProofRegistry.submitProof(_legalProof);
token.setFrozenToken(_user, _tokenId, _amount);
}
}
Thanks folks !
Iāve:
- Added an āExtensibilityā section to talk about all the possibilities of batching, using multicall or modifiers to extend functionalities and add for example legalProofs. Iāve used your example there @tinom9 . Wdyt about this @radek ?
- Changed the
ERC7943InsufficientUnfrozenBalanceerror of the non-fungible example to something more clear and appropiateERC7943FrozenTokenId. - Made the description of the usage of such errors more clear now that interfaces are split
- Added
msg.senderas potential context in thecanTransferfunction.
Checks commit here ā Update ERC-7943: Split into separate interfaces by xaler5 Ā· Pull Request #1210 Ā· ethereum/ERCs Ā· GitHub
The only thing that Iāve not addressed is the redundancy of checks within the reference implementation as suggested by @Bryn_Hacken. The reason is that the redundancy is inherent on how OZ contracts work tbh and might not apply to other implementations that use different patterns for inheritance.
Overall this looks rock solid to me now. What I wish to do before moving this into a final state is:
- Triple check the description chasing for typos, things that might be explained better or missing specs
- Have confirmation that this is backward compatible with ERC-3643, @Joachim-Lebrun can you double check this ?
Amazing work so to everyone
The interface split makes it much more clear.
Wrt legal proof params ā I like the concept of the separation of concerns on the conceptual/logical level. However, on the smart contract (SC) level, this creates requirements on further deployments/audits, while the general extension has a minimalistic impact.
It is common to have impacting methods extended with calldata data.
If the semantics of legalProof are too concrete, I propose to consider:
function forcedTransfer(address from, address to, uint256 amount, bytes calldata auxiliaryData) external;
function setFrozenTokens(address user, uint256 amount, bytes calldata auxiliaryData) external;
Thus, those that do not need it just use 0x as the auxiliaryData.
Anyhow, as mentioned by @SamWilsn and based on some other standardās experiences, the minimalist approach fits more in the long term.
Therefore, I propose to split this ERC into 2:
- Minimalist ERC with read-only functions.
- Extension with
setFrozenTokensandforcedTransfer.
Similarly, like ERC-20, which does not have mint/burn, which is described as an extension in ERC-5679.
In the forceTransfer spec, it mentions optionally bypassing freezing validations and emitting a Frozen event before the base transfer event to handle reentrancy risks. Shouldnāt we make this event emission order mandatory in the standard since that could be a significant security issue?
About the legalProof parameter, I believe itās a useful use case, but adding it to the interface will automatically break compatibility with already existing standards like 3643 that doesnāt expose that. Thatās why is probably a good thing to keep it as a possible extension so that backward compatibility is not necessarily broken.
In this regard I believe @tinom9 proposal is sound and doesnāt break any compatibility.
In regard of splitting read-only functions with state-changing one I see your point. The interface has already been split into 3 (erc20/erc721/erc1155) to enable backward compatibility. I strongly believe that state-changing functions must stay in the standard because while I agree with @SamWilsn on that these functions might be generally called by issuers/owners I also foresee automated integrations where callers will be other specialized smart contracts. For this it is valuable to keep them standardized and in-scope.
My main concern on splitting further is how much fragmented this ERC can become if that happens. I will still think a bit about that, just wanted to share thoughts.
@phiraml I believe what you suggested is already mandated isnāt it ?
It CAN bypass the freezing validations and update the freezing status accordingly. Only if this happens, it MUST unfreeze the assets first and emit a
Frozenevent before the underlying base token transfer event reflecting the change.
Or are you suggesting changing that to
It CAN bypass the freezing validations and update the freezing status accordingly. Only if this happens, it MUST unfreeze the assets first and MUST emit a
Frozenevent before the underlying base token transfer event reflecting the change.
(Added a MUST before āemitā).
Iāve also opened up a PR here Update ERC-7943: [WIP] Add delta freezes, fix backward compatibility by xaler5 Ā· Pull Request #1236 Ā· ethereum/ERCs Ā· GitHub
With the following changes:
-
Added a return boolean value to
forcedTransferto match exactly 3643. -
Additionally, since
setFrozenTokensis not part of any other EIP, we have freedom to make it more powerful. My proposition here is to make theamountparameter a signed integer so that it can handle deltas and we can get rid of the front-run issue scenario. An analysis of how it can behave:- From 0 to positive X it acts as absolute (receives positive int as input)
- From positive X to positive Y>X it acts as incremental positive delta (receives positive int)
- From positive X to positive Y<X it acts as incremental negative delta (receives negative int)
- It can never go below 0
having said that Iād like to know:
- What do you think about this change in
setFrozenTokens? If you like it, should it return a bool asforcedTransferto improve consistency overall ? - On a side note, 3643 defines
isVerifiedin the identity registry interface, which would be the equivalent of theisUserAllowedhere in 7943. Even if 7943 keeps this within the same token interface, wdyt about changinisUserAllowedtoisVerifiedand make it consistent also with 3643 ? This is not mandatory since backward compatibility is not broken either way but would align on naming. I feel āverifiedā sounds a bit more specific than āis allowedā but have no strong feelings neither.
I think isVerified is better; itās also align with ERC-7734 isVerified are attributes in the Identity struct.
isVerified is IMHO too narrow in the semantics - even from AML perspective. AML verification is reflecting identity process, while I understood the function itself reflects many other conditions resulting in allowance to interact.
I am not saying isUserAllowed is ideal. The contract is disallowing a certain Account, not User as it does not handle the User identity here.
Also please bear in mind that we have one flat namespace in ABI for the whole contract.
On one hand - look at OZ 5+ where the approval increment / decrement functions were removed as not needed considering FR attacks too hypothetical in approve case.
On the other hand I do not understand, why the approve() function was setting absolute value when it is used to increase/decrease allowance, i.e. change.