Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NEP-5 Amendment #44

Merged
merged 5 commits into from
Jun 25, 2018
Merged
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 54 additions & 18 deletions nep-5.mediawiki
Original file line number Diff line number Diff line change
Expand Up @@ -19,55 +19,91 @@ As the NEO blockchain scales, Smart Contract deployment and invocation will beco

In the method definitions below, we provide both the definitions of the functions as they are defined in the contract as well as the invoke parameters.

This standard defines two method types:

* '''(Required)''' : methods that are present on all NEP5 tokens.

===Methods===

====totalSupply====

* Syntax: <code>public static BigInteger totalSupply()</code>
<pre>
public static BigInteger totalSupply()
</pre>

* Remarks: "totalSupply" returns the total token supply deployed in the system.
Returns the total token supply deployed in the system.

====name====

* Syntax: <code>public static string name()</code>
<pre>
public static string name()
</pre>

* Remarks: "name" returns the token name.
Returns the name of the token. e.g. <code>"MyToken"</code>.

This method MUST always return the same value every time it is invoked.

====symbol====

* Syntax: <code>public static string symbol()</code>
<pre>
public static string symbol()
</pre>

Returns a short string symbol of the token managed in this contract. e.g. <code>"MYT"</code>. This symbol SHOULD be short (3-8 characters is recommended), with no whitespace characters or new-lines and SHOULD be limited to the uppercase latin alphabet (i.e. the 26 letters used in English).

* Remarks: "symbol" returns the token symbol.
This method MUST always return the same value every time it is invoked.

====decimals====

* Syntax: <code>public static byte decimals()</code>
<pre>
public static byte decimals()
</pre>

* Remarks: "decimals" returns the number of decimals used by the token.
Returns the number of decimals used by the token - e.g. <code>8</code>, means to divide the token amount by <code>100,000,000</code> to get its user representation.

This method MUST always return the same value every time it is invoked.

====balanceOf====

* Syntax: <code>public static BigInteger balanceOf(byte[] account)</code>
<pre>
public static BigInteger balanceOf(byte[] account)
</pre>

* Remarks: "balanceOf" returns the token balance of the '''account'''.
Returns the token balance of the <code>account</code>.

The parameter <code>account</code> SHOULD be a 20-byte address. If not, this method SHOULD <code>throw</code> an exception.

If the <code>account</code> is an unused address, this method SHOULD return <code>0</code>.

====transfer====

* Syntax: <code>public static bool transfer(byte[] from, byte[] to, BigInteger amount)</code>
<pre>
public static bool transfer(byte[] from, byte[] to, BigInteger amount)
</pre>

Transfers an <code>amount</code> of tokens from the <code>from</code> account to the <code>to</code> account.

The parameters <code>from</code> and <code>to</code> SHOULD be 20-byte addresses. If not, this method SHOULD <code>throw</code> an exception.

The parameter <code>amount</code> SHOULD be greater than or equal to <code>0</code>. If not, this method SHOULD <code>throw</code> an exception.

* Remarks: "transfer" will transfer an '''amount''' of tokens from the '''from''' account to the '''to''' account. Contract '''MUST''' check the <code>payable</code> flag of the receiver contracts to decide whether it should transfer the tokens to those contracts.
The function SHOULD return <code>false</code> if the <code>from</code> account balance does not have enough tokens to spend.

If the method succeeds, it MUST fire the <code>transfer</code> event, and MUST return <code>true</code>, even if the <code>amount</code> is <code>0</code>, or <code>from</code> and <code>to</code> are the same address.

The function SHOULD check whether the <code>from</code> address equals the caller contract hash. If so, the transfer SHOULD be processed; If not, the function SHOULD use the SYSCALL <code>Neo.Runtime.CheckWitness</code> to verify the transfer.

If the <code>to</code> address is a deployed contract, the function SHOULD check the <code>payable</code> flag of this contract to decide whether it should transfer the tokens to this contract.

If the transfer is not processed, the function SHOULD return <code>false</code>.

===Events===

====transfer====

* Syntax: <code>public static event Action<byte[], byte[], BigInteger> transfer</code>
<pre>
public static event transfer(byte[] from, byte[] to, BigInteger amount)
</pre>

MUST trigger when tokens are transferred, including zero value transfers.

* Remarks: The "transfer" event is raised after a successful execution of the "transfer" method.
A token contract which creates new tokens SHOULD trigger a <code>transfer</code> event with the <code>from</code> address set to <code>null</code> when tokens are created.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1000 on this!

This was not in the original NEP5, but block explorers like neotracker or neoscan depend on this event to be called when tokens are minted. So there have been cases where this notification was not emitted at the time of minting, and resulted in confusion for users who would see their tokens in their wallets, but not on the explorer. Until they make a transfer.

Hopefully this will prevent that from happening in the future.

That being said, would it be possible to update this from a SHOULD to a MUST?

Copy link

@nickfujita nickfujita Jun 6, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After further consideration, I am starting to wonder if it makes more sense to remove this clause from the transfer event. The ask is to have the transfer event triggered from a method that is not a part of the NEP5 standard. Whether it be though a token sale, direct allocation method, or some dynamic token creation event, these all result in an action more akin to that of a mintToken or mint event, rather than a transfer that is inferred to be a mint when the from"address is null.

The desire for a separate event for token creation (and even token burn) have been expressed a few times in other posts.

#39

CityOfZion/neo-python#457

I would like to reaffirm the proposal stated in the latter thread, with more urgency on the mint or mintToken event over the burn or burnToken event.

mint or mintToken

public static event mint(byte[] to, BigInteger amount)
public static event mintToken(byte[] to, BigInteger amount)

MUST trigger when tokens are minted.

burn or burnToken

public static event burn(byte[] from, BigInteger amount)
public static event burnToken(byte[] from, BigInteger amount)

MUST trigger when tokens are burned.

These events will help to increase transparency into contract mint and burn events amongst users, and possibly improve confidence that tokens are not being minted unknowingly.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Too many events. The standard should be as simple as possible.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While I agree that the standard should be simple to understand and implement, shouldn't it also be descriptively accurate?

Rather than adding the SHOULD clause to the transfer event, it seems more accurate to create a separate event called mint. I understand that the implication that tokens are being transferred from null because they are being created, but this implication assumes this prior knowledge from a reader rather than being clear and self explanatory.

Could we please reconsider just the addition of the mint event to clean up the notifications being emitted by contracts?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't quite see the need for a mint/burn event myself either. Seeing funds created/destroyed by coming from/to null shows that the tokens either came from nowhere or were sent to nowhere.

+1 on changing the SHOULD to a MUST though. If tokens are being created/destroyed it is good to be able to pick this up without checking TotalSupply constantly and inferring the change. Having the change notification arise out of a certain block is a much cleaner way to show it.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


==Implementation==

Expand Down