Discover more from Fairyproof Official Newsletter
Security Considerations on Implementing EIP-3525 Based Tokens
EIP-3525 is a newly submitted proposal to create semi-fungible tokens. Here are some security points that implementers need to consider.
EIP-3525¹ is a newly submitted proposal to create semi-fungible tokens.
This EIP is created to solve the drawbacks in either EIP-20 or EIP-721 when creating tokenized financial instruments that should allow their holders to transfer a portion of the equity in the contracts represented by the tokens.
We can, then, imagine instances of tokens possessing features of both fungible (Mainly implemented based on EIP-20) and non-fungible (Mainly implemented based on EIP-721 or EIP-1155) tokens, cannot be elegantly implemented based on any of the existing EIPs.
A token implemented based on this EIP has both the “Balanced” feature of fungible tokens and the “Uniqueness” of non-fungible tokens. In this EIP, the former is defined as “Value”, and the latter is defined as “ID”. The combination of these two features allows us to derive this EIP to be “semi-fungible”.
Apart from the “Value” and the “ID”, this EIP also introduces a third element “SLOT” to define a token’s fungibility. When two IDs have the same SLOT, the two tokens defined by these two IDs are therefore fungible; otherwise, they would be considered non-fungible.
Therefore, the essence of this EIP is that it uses a <ID, SLOT, VALUE> triple scalar to represent the semi-fungible structure of a token.
As a blockchain security company, Fairyproof always has a strong focus on the study, research, and analysis of EIPs and their security issues. Hence, with regards to EIP-3525, there are some security points implementers must pay attention to if we dive deep into possible implementations of tokens based on this EIP:
1. Encouraging Storage of Key Metadata On-Chain
A prominent area of implementation involving EIP-3525 is in tokenized financial instruments. As compared to those based on conventional technologies for financial applications, blockchain-based applications’ greatest advantages are transparency, public accessibility, and tamper-proof. These advantages are achieved by placing data on-chain.
When implementers implement financial tokens based on this EIP, we strongly encourage them to place their key data on-chain. We define a financial instrument’s key data as those needed to define its return and risks — Such as ROI, redemption time, risk rating, time-of-issuance, amount, and more.
Other details may not necessarily be on-chain.
When auditing a financial token implemented based on EIP-3525, we strongly suggest to check if the key data defined as metadata are stored on-chain.
2. Access Control to Privileged Functions
From Fairyproof’s perspective, functions like “mint”, “burn”, and “approve” are categorized as privileged functions as they are likely to cause fatal damages to a token that implement said functions should they be compromised. Apart from the regular “mint”, “burn”, and “approve” functions defined in both EIP-20 and EIP721/EIP-1155 (Which are also defined in this EIP), there are two new privileged functions defined in this EIP-3525:
i) “approve(uint256 _tokenId, address _operator, uint256 _value) external payable”, which is called to approve “_operator” to transfer up to “value” quantity of tokens of “_tokenId”.
ii) “setApprovalForSlot(address _owner, uint256 _slot, address _operator, bool _approved) external payable”, which is called to approve/disapprove “_operator” to transfer tokens of “_slot” from “_owner”.
All of these functions should usually be called by the admin or authorized addresses with great care. If their access control is compromised and these functions are called maliciously, unexpected risks would be introduced.
To mitigate this risk, the access control to these privileged functions should be transferred to a multi-sig wallet or DAO.
3. Issues with SLOT Related Functions
“SLOT” is a new parameter introduced in this EIP. It defines whether the tokens of different tokenIds are fungible.
In this EIP, the “write” functions that work based on a “slot” besides the “setApprovalForSlot” function include those as follows:
I) “transferFrom(uint256 _fromTokenId, uint256 _toTokenId, uint256 _value) external payable”, which is called to transfer “_value” quantity of tokens from “_fromTokenId” to “_toTokenId”. The “_fromTokenId” and the “_toTokenId” should have the same slot.
II) “transferFrom(uint256 _fromTokenId, address _to, uint256 _value) external payable returns (uint256)”, which is called to transfer “_value” quantity of tokens from “_fromTokenId” to “_to”.
Both functions require the receiver to possess tokens with the same slot as the sender. Specifically for the second function shown above, two cases should be handled with care:
a) If the receiver does not have tokens of said slot, the implementer should create/mint a token of the slot for the receiver.
b) If the receiver has multiple TokenIds of the slot, any one or multiple of the TokenIds could be treated as the receiver(s). For instance: If there are two TokenIds of the slot (TokenId A and TokenID B), either the whole “_value” could be added to TokenId A, or a part of “_value” can be assigned to TokenId A while the remaining is assigned to TokenId B.
Cases a) and b) introduce implementation complexity — Case b) in particular provides large implementation flexibilities. When implementing this function, the implementer should strictly follow the application’s business logic; otherwise, issues with incorrect implementation may occur.
When auditing these functions, besides the regular technical issues, business logic should be carefully audited as well. It is strongly suggested to check the application’s business logic and make sure the functions’ behaviors match the business logic and no vulnerabilities with business logic would occur.
4. Potential Issues with “onERC3525Received”
The “OnERC3525Received” function is defined to handle the subsequent logic after an EIP-3525 token is transferred to a smart contract address. If the function is implemented, it should be called and the return value of the “OnERC3525Received” function should be “0x009ce20b” if the token is accepted. It also means that EIP-3525 tokens can be rejected if the “OnERC3525Received” function returns an alternative value.
This feature can be implemented as a blacklist/whitelist function. Implementers, handle this with caution.
When auditing a smart contract that receives EIP-3525 tokens, if the “OnERC3525Received” function is implemented in the smart contract, the logic to call this function and the handling of its consequence of the call should be reviewed to avoid incorrect instances of acceptance or rejection of EIP-3525 tokens.
In summary, as a blockchain security company, when we audit tokens implemented based on EIP-3525 we would cover these three areas:
i) From an implementation point of view:
We would check whether the tokens’ core data is saved on-chain to ensure their publicity, transparency and tamper-proof.
We would also check whether the “OnERC3525Received” function is properly called to ensure EIP-3525 tokens are correctly accepted or rejected if the function is implemented.
ii) From a technical point of view:
We check whether the access control to the privileged functions is safely and securely managed and maintained.
iii) From a tokenomics point of view:
We would check whether the slot related functions’ behaviors match the token’s tokenomics.
¹EIP-3525: Semi-Fungible Token, https://eips.ethereum.org/EIPS/eip-3525