NEP: 27 Title: Smart contract transfer callback for fungible tokens Author: Erik Zhang <[email protected]>, Roman Khimov <[email protected]>, Jaime Kindelan <[email protected]>, Jimmy Liao <[email protected]> Type: Informational Status: Final Created: 2024-03-03 Requires: 17
This proposal describes the callback method used by Neo smart contracts to process transfers of fungible NEP-17 tokens to their addresses.
While the original NEP-17 already defines this method, it
lacks some details relevant specifically to the receiver contract and it doesn't
allow for easy reference. This standard can be used in supportedstandards
section of NEP-15 manifest or in any other situation to
refer to contracts able to receive NEP-17 tokens (but not
necessarily being NEP-17 themselves). Typical use cases
for this functionality are: depositing/staking (with contract locking and
managing tokens according to some rules) or exchange/minting (contract accepting
transfer to itself, but returning some different token to the sender).
Smart contracts that need to receive and own NEP-17 tokens
MUST implement onNEP17Payment
method with the following signature:
{ "name": "onNEP17Payment", "parameters": [ { "name": "from", "type": "Hash160" }, { "name": "amount", "type": "Integer" }, { "name": "data", "type": "Any" } ], "returntype": "Void" }
A contract that doesn't implement this method will not be able to receive
NEP-17 tokens standard requires this method to be called
unconditionally which will fail at the system call level if it's not implemented
which then leads to a complete transaction failure). This method is called by
NEP-17 contracts which tokens are being transferred. A
particular token can be obtained via the System.Runtime.GetCallingScriptHash
system call. Notice that technically this method MAY be called by entry scripts or
non-NEP-17 contracts as well, so contracts SHOULD check for
caller script hash to match their expectations like allowed/accepted tokens.
Processing this call means that contract trusts the caller to implement
NEP-17 correctly.
from
parameter specifies the sender of tokens and can be null
for minted tokens.
amount
is the amount of tokens transferred to the contract.
data
is the same data
parameter that was given to the
NEP-17 transfer
call. Contract can interpret
it in any application-specific way including imposing any restrictions on
accepted data
contents.
If the contract implementing this NEP can't accept the transfer (for reasons like
unexpected token, wrong amount, forbidden sender, wrong data
parameter or any other) it MUST call ABORT
or ABORTMSG
VM opcode to fail the transaction. This is the only way to ensure contract
won't own transferred tokens, because the method doesn't return any value
and exceptions can be handled by calling contract. Contact MAY also check for
various conditions with ASSERT
or ASSERTMSG
opcodes.
This NEP just follows and explains NEP-17 semantics, no design decisions made here.
This NEP is completely compatible with NEP-17, there are just two extensions to it:
- addition of
ABORTMSG
opcode that didn't exist at the time of NEP-17 creation, but it's the same thing asABORT
semantically. - explicit
ASSERT
andASSERTMSG
opcode allowance that was not a part of NEP-17, but also has the same function asABORT
for failed conditions.
- https://github.com/nspcc-dev/neo-go/blob/8d67f17943553740fe4caa31c3e9efcf7921aba2/examples/nft-nd/nft.go#L213
- https://github.com/nspcc-dev/neofs-contract/blob/91962f2c5625d8aab42adde138f2411c52393382/contracts/neofs/contract.go#L237
- https://github.com/neoburger/code/blob/beb433288bd7b0da9d2245e2a0ae5af5309da7ed/BurgerNEO.cs#L42