ERC-5750: General Extensibility
ERC-5750 standardises the use of a trailing bytes calldata parameter on public methods so future extensions can add behavior without changing the method's selector. The trailing parameter is opaque to the base implementation; extensions interpret it (e.g. permit signature, fee recipient hint, EIP-712 typed-data context).
Used by:
- NEP-17 / ERC-20-style transfers with optional permit / meta-tx data.
- NFT transfers with optional payment hints.
- Generic action methods that may grow new flags / context.
This is a convention, not an interface — there's no specific method to implement; rather, every method should adopt the trailing-data shape.
The Pattern
function transfer(address from, address to, uint256 amount, bytes calldata extension)
external returns (bool);If extension.length == 0: behave as a normal transfer. Otherwise: the implementation may parse extension to apply additional behaviors (e.g. atomic permit, fee config, callback data).
Neo Equivalent: NEP-17 / NEP-11 Already Do This
NEP-17 mandates the four-parameter transfer(from, to, amount, data) signature where data is the trailing extensibility slot — forwarded to the recipient's OnNEP17Payment callback. Neo bakes ERC-5750's convention into the base NEP-17 / NEP-11 standards from day one.
| ERC-5750 (Ethereum) | Neo Equivalent | Notes |
|---|---|---|
Trailing bytes calldata extension parameter | NEP-17 / NEP-11 trailing data parameter | Native to NEP standards |
| Empty extension = base behavior | data == null = base behavior | Direct equivalent |
| Extensions interpret extension bytes | Application uses data for callback context, fee hints, etc. | Same affordance |
Migration Notes
For Solidity contracts adopting ERC-5750 conventions, the Neo port already has this through NEP-17 / NEP-11 base. No additional work needed — every NEP-style transfer has the trailing data parameter by spec.
For application contracts (not just tokens), follow the same pattern: append a trailing object data parameter to public methods that might gain new behaviors.
public static void DoSomething(BigInteger amount, object data)
{
// Base behavior.
DoBaseAction(amount);
// Optional extension via data parameter.
if (data is not null)
{
var ext = (Map<string, object>)data;
if (ext.HasKey("permit")) ApplyPermit((ByteString)ext["permit"]);
if (ext.HasKey("fee_hint")) RouteFee((BigInteger)ext["fee_hint"]);
}
}