standard · execution

LUKSO LSP1 Universal Receiver Standard

LSP·1 · Execution

One receiver hook for every asset type, every transfer, every contract-to-contract notification.

LSP·1 interface solidity
// The single hook every LSP1-aware contract implements.
function universalReceiver(bytes32 typeId, bytes memory receivedData)
  external payable returns (bytes memory);

// typeId is a fixed selector (e.g. LSP7Tokens_RecipientNotification)
// data carries the call-site payload (transfer details, asset address, etc.)

LSP1 is the structural fix to the “one receiver interface per asset standard” problem. Every LSP that moves value or transfers ownership calls universalReceiver on both sides with a fixed typeId and a payload. A contract that wants to react implements one function and dispatches on typeId — there is no onLSP7Received / onLSP8Received / onLSPxxReceived.

Universal Profiles pair LSP1 with a Universal Receiver Delegate: a small companion contract the profile delegates to, where you write the actual policy (register asset in LSP5, reject by typeId, route to a sub-contract, etc.). The delegate is replaceable per profile.

What it solves.

What it does not solve.

Anti-overselling is a feature.

  • LSP1 does not specify *what* to do when receiving. That's the Universal Receiver Delegate's job.
  • Reentrancy guarantees are the implementer's responsibility, same as any onERC*Received hook.
  • Only fires when the sender explicitly calls it. Plain ETH `transfer` and ERC-20 `transfer` don't, so LSP1 can't catch every kind of inbound value.
  • typeId is fixed bytes32 with no schema registry — the meaning of payload bytes is a per-typeId contract that both sides must agree on.

Companions.

Standards this composes with.

Read the source.