ERC-1155 Standard Violations Remediation
Overview
ERC-1155 compliance failures cluster in three places: batch operations that skip the parallel-array length check, safe transfers that never call the receiver callbacks, and missing ERC-165 declarations that break integration discovery. The first is the most dangerous — mismatched ids[]/amounts[] arrays corrupt transfers — and the second permanently locks tokens sent to non-receiver contracts. The reliable remediation for all of them is the same: inherit an audited implementation rather than hand-rolling the standard.
Related Detector: ERC-1155 Standard Violations
Recommended Fix
Before (Vulnerable)
contract MultiToken {
mapping(uint256 => mapping(address => uint256)) public balances;
function safeBatchTransferFrom(
address from, address to,
uint256[] calldata ids, uint256[] calldata amounts, bytes calldata
) external {
// No length check, no zero-address check, no receiver callback
for (uint256 i = 0; i < ids.length; i++) {
balances[ids[i]][from] -= amounts[i];
balances[ids[i]][to] += amounts[i];
}
}
}
After (Fixed)
import {ERC1155} from "@openzeppelin/contracts/token/ERC1155/ERC1155.sol";
contract MultiToken is ERC1155 {
constructor() ERC1155("https://token.example/{id}.json") {}
// Inherited safeBatchTransferFrom validates array lengths and the
// zero address, emits TransferBatch, and verifies
// onERC1155BatchReceived on contract recipients.
}
The inherited implementation enforces every requirement the detector checks: ids.length == amounts.length, to != address(0), effects-before-callback ordering, correct events, and supportsInterface declarations for both IERC1155 and IERC1155MetadataURI.
Alternative Mitigations
If a custom implementation is unavoidable, apply the checks in this order inside each safe-transfer function:
require(to != address(0))and, for batches,require(ids.length == amounts.length).- Update all balances (effects).
- Emit
TransferSingle/TransferBatch. - Only then invoke
onERC1155Received/onERC1155BatchReceivedon contract recipients and require the magic return value.
Step ordering doubles as reentrancy protection: a malicious receiver re-entering from the callback observes fully updated balances.
Common Mistakes
- Checking the callback only in the single-transfer path.
safeBatchTransferFromneedsonERC1155BatchReceived, a different selector — implementing one and forwarding to the other is a common shortcut that breaks receivers expecting the batch hook. - Calling the receiver before writing balances. That converts the mandated callback into a reentrancy window.
- Skipping the length check because “our frontend always sends matching arrays.” The function is public; attackers do not use your frontend.
- Forgetting
supportsInterface. Marketplaces probe ERC-165 before listing; without it the token is compliant in behavior but invisible in practice.