-
Notifications
You must be signed in to change notification settings - Fork 13
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
AIP-040: Application standard for non-fungible tokens #40
Comments
@fulldecent Thank you for submitting! The AIP number for this can be #40. |
@fulldecent The method name in this AIP starts with aip#. Example: aip010OwnerOf(byte[]) Is it a good practice to include AIP# in the method name ? With AIP# in class name, it seems to be redundant. |
@satran004 Whether this is a best practice or not is still open for discussion, comments welcome. Related discussion also at https://github.com/fulldecent/aip-xxx-implementation The specific problem we are trying to avoid is one AIP defines a standard function name like Another problem is introspection -- querying a contract to learn if it implements a certain interface, for example, this token standard. If you just call |
Thanks @fulldecent. Now I understand the reasoning behind the naming. If the idea is to avoid conflict when the class implements two AIP interfaces with same method name, does it make sense to have a contract functionality specific prefix instead of AIP#?
Let me give a similar comparison in JSR standard (Java Specification Requirement). |
This is the exact problem we are having in the Ethereum space. The problem is that two people will claim to be the authority on NFT. In EIPs, we have ERC-721 and now ERC-1155. The ERC-1155 could not maintain backwards compatibility with ERC-721 because the latter wanted to reuse function names for different purposes. (Not to mention details about ERC-820/821 DRAFT, ERC-841 DRAFT, ERC-875 DRAFT and other competing NFT standards.) Having namespacing like "nft" will work if there is one editor that has strong editorial control over the corpus of interfaces. However if there are multiple authors then it is enviable that multiple people will compete to standardize the names. Using an AIP number avoids this problem because there is a central editor that assigns AIP numbers and avoids conflicts. |
Changing the status to Discussion |
Added specification for tokenId padding at 86374e0 and added specification with rationale to AIP. |
AIP: 040
Title: Aion Non-Fungible Token Standard
Author(s): William Entriken
Type: ASC
Status: Discussion
Creation Date: 2019-07-05
Contact Information: [email protected]
📖 OPEN ITEMS
TODO: Reference implementation blockers to deploy: https://github.com/fulldecent/aion-aip040/milestone/1
TODO: Deploy reference implementation, link here
TODO: Discuss naming of things: deauthorize/revoke (compare with AIP-041), and consign/offer
Add any steps here for AIP process
Summary
A standard interface for non-fungible tokens ("NFTs"), also known as deeds.
Value Proposition
The following standard provides basic functionality for Aion AVM contracts to track and transfer NFTs. It builds on a wealth of experience seen from existing NFT implementations in the real world.
We considered use cases of NFTs being owned and transacted by individuals as well as being entrusted to third party brokers/wallets/auctioneers. NFTs can represent ownership over digital or physical assets. We considered a diverse universe of assets, and we know you will dream up many more:
On-chain assets — in-game items, ownership of contracts, authority to use contracts
Certificates — official digital registration of an off-chain thing, identity, proof of authenticity, supply chain
Lots — a security which can be redeemed to take possession of an underlying real-world asset
“Negative value” assets — loans, burdens and other responsibilities
In general, all houses are distinct and no two kittens are alike. NFTs are distinguishable and you must track the ownership of each one separately.
Remember:
Motivation
A standard interface allows wallet/broker/auction applications to work with any NFT on Aion. We provide for simple NFT smart contracts as well as contracts that track an arbitrarily large number of NFTs.
This standard is inspired by AIP-041 Aion Token Standard (DRAFT), ERC-721 Non-Fungible Token Standard and ERC-1155 Multi Token Standard. The Aion Token Standard is sufficient for tracking many types of tokens, however non-fungible tokens are a distinct asset class which is not compatible.
This supposes specific use cases of non-fungible tokens, however the design is created in a way to support all of the identified use cases without prescribing how they do it. Be creative, we encourage you to make extensions and use this in many ways.
Non-Goals
We do not intend to prevent competing non-fungible token standards from developing on Aion. We hope this standard is useful so that other authors will choose to be compatible with this if they will write their own standard.
Success Metrics
Description
This specification comprises an interface which is adhered to by all conforming AIP-040 producers (i.e. token contracts) and which is expected by all AIP-040 consumers (e.g. wallets/brokers/auction applications).
Specification
The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in RFC 2119.
A contract which implements AIP-040 MUST expose at least this Aion application binary interface (the qualified class name is not part of the specification) and follow all prescriptions below:
Aion contracts are classes which expose functionality using
public static
methods. A contract which implements AIP-040 MUST implement each method specified in theAIP040
interface below, including all@apiSpec
annotations. Reference is made to theorg.aion.avm.Address
type and this is imported from the AVM jar.You cannot use the above code as an
implements
target for your implementation code. Java does not support class (not instance) methods with dynamic dispatch, so we cannot make aninterface
for Aion contracts. This is a shortcoming of Java and should be addressed as a Java Specification Request. And/or the author of this document does not know Java well enough.A contract which implements AIP-040 MUST emit each event as specified in the
AIP040Events
interface below, including all@apiSpec
annotations. Reference is made to theorg.aion.avm.Address
type and this is imported from the AVM jar.JSON
If the token URI is JSON, or if it is a URL that points to JSON then that JSON MUST conform to the following format.
The only specified requirement is that the root object is a JSON object and that the properties "name," "description," and "image," if included, will be a
String
and will have the meaning shown above.Caveats
java.math.BigInteger
ABI type, currently this feature is not yet released.Logic
The design and specification are based on ERC-721 with changes based on a new understanding of best practices and use cases that have evolved since that specification was published, as well as best practices that were available at that time but which failed to be recognized.
Transfer Mechanism — Withdraw Pattern
This standard provides only one transfer mechanism: taking ownership of a specific token where you are permitted to do so. Permission is granted either on a per-token basis (consignment) or a per-account basis (authorization). Permission MAY be limited for any other application-specific reasons, temporary or permanent.
This mechanism is called the Withdraw Pattern. Details and security considerations which show the benefits of this mechanism as applied to smart contracts are presented in the Solidity documentation, Common Patterns.
This protects against specific mistakes and attacks where other, more featured transfer mechanisms are vulnerable:
gasLimit
Appropriately Enables Abuse". This is impossible with the AIP-040 standard transfer mechanism because every transfer is performed by the recipient.Transfer Mechanism — No Additional Data
This standard's transfer mechanism does not include the ability to pass opaque data (e.g. "user bytes") along with a token. This is a direct consequence of standardizing on the withdraw pattern. The transfer is performed by the recipient so passing bytes to the recipient serves no purpose.
If you had considered using opaque transfer data for an ERC-721 contract for an application-specific transfer such as listing tokens for sale at a user-supplied price:
then with AIP-040 please consider to use a custom method that more clearly articulates the intent:
In the vast majority of cases, we see that token owners are interacting with auction contracts by authorizing access on all of their tokens. Therefore consignment is rarely used for those scenarios.
Similarly, this specification does not allow passing data back to the previous token owner, for the same "wasteful recipient" reason explained above.
Transfer Mechanism — Batch
The transfer and consignment mechanisms accept the token IDs in batch as an array. Failure to include batch transfers in ERC-721 was a common source of complaints and a primary motivation for the creation of ERC-1155, a replacement/extension to ERC-721 as well as numerous other draft standardization proposals.
Only batch transfers are allowed. To transfer one token, use
takeOwnership
with an array having length one.In the reference implementation, we created a separate method which allowed transfer without using an array. This saves the cost of having to deserialize an array when only one token is transferred. The cost as in the current proposal for transferring one token is 220037 and with a new hypothetical takeOneToken function it is 219536. The savings is 0.22% over baseline. We do not recognize this as an appreciable savings and have chosen the simplicity of having one transfer function, using arrays.
Alternatives considered: include separate batch and non-batch transfer methods.
Interface Detection
All standardized methods and events are named with the prefix "aip040". This disambiguates the meaning entirely. We identify this as best practice for Aion standardized interfaces because Aion allows you to see the called method names for every transaction. On other blockchains the method/function name is hashed and the original name is not recoverable. Therefore on other blockchains a workaround such as ERC-165 is necessary to find the supported standard interfaces. To detect a contract on Aion which implements simply listen for the events are call one of the methods such as
aip040Symbol
.Alternatives considered included: use an application-specific prefix like "token" or "nft" (bad, would overlap with other token standards), don't use a prefix (bad, would definitely overlap).
Naming
The word "take" in
aip040TakeOwnership
is chosen instead of withdraw because it is short, more direct and because some people may not know the difference between withdraw and withdrawal. This choice is also consistent with the Aion Voice Guidelines.The words "consign," "authorize," and "deauthorize" are chosen in
aip040Consign
,aip040Authorize
andaip040Authorize
respectively. These words are chosen to match the plain meaning of these words and avoid jargon such as "approve" in ERC-20, and "setApprovalForAll" in ERC-721.Events use names as verbs having past tense and title case,
AIP040Transferred
,AIP040Consigned
,AIP040Authorized
,AIP040Deauthorized
. This is the modern pattern used in smart contracts such as AIP-041 (DRAFT) and ERC-721. Other standards use present simple tense and nouns (e.g.TransferSingle
,Approval
) such as ERC-20 and ERC-1155. We choose to prefer style from AIP-041. The word "transferred" is used rather than "taken" because it applies more generally, including minting and burning operations.The methods
aip040TokenAtIndex
andaip040TokenForOwnerAtIndex
allow to access an element of an array and of an array inside a mapping. We recommend as best practice that method names which refer to accessing the element of an array with a specified index (ordinal) should use "at" and accessing the element of a mapping should use "for". This follows the concept that arrays are predicated on an ordinal input, representing a location in a list ("at") and is consistent with Java documentation for lists. We see "for" as a more general predicate which does not indicate location, making it appropriate for mappings. This is a departure from ERC-721 which uses "of," which we see as more relevant for an object property.Authorize and Deauthorize
The authorize and deauthorize methods are separated. This is consistent with AIP-041 and is a departure from ERC-721, ERC-1155. We find that including booleans as a method argument is usually not best practice and cite Martin Fowler on this topic.
TODO: Harmonize mechanism and naming with AIP-041 fulldecent/aion-aip040#34.
Enumeration
Four methods allow you to query information from an AIP-040 contract which could have been queried by inspecting the transactions,
aip040TotalSupply()
,aip040OwnerBalance(Address)
,aip040TokenAtIndex(BigInteger)
andaip040TokenForOwnerAtIndex(Address, BigInteger)
. Maintaining the accounting for these methods requires additional resources than a simpler hypothetical standard could need.Certain token implementations such as ERC-1155 and the baseline ERC-721 do not provide enumeration of owned tokens. This approach is less expensive to implement on-chain. However wallet applications will need to scan historical blockchain events, possibly for the entire blockchain to find the tokens of a specific owner. These scanned results could be cached.
The decision was made in AIP-040 to require all implementations to support the full transparency of enumeration. This enables lightweight wallet applications that do not require scanning.
JSON
The AIP-040 token metadata standard is copied from the ERC-721 Metadata JSON Schema. This is a widely permissive standard and is compatible with the following more strict specifications:
Token Identifiers
Tokens identifiers are used to differentiate tokens. In the universe of use cases we have reviewed we also expect to see tokens that are a hash of some specific content, for example a hash of a JSON file. This means that we should expect token identifiers for some applications at least in the range [0, 2^256).
In AIP-040, tokens are identified by using
java.math.BigInteger
(which is shadowed by the Aion virtual machine). These allow positive, negative and zero as valid identifiers. Aion limits this type to 32 bytes, with values ranging from -2^255 thru 2^255-1, inclusive. Java programmers will recognize the similarity withbyte
which actually has a range from -128 thru 127, inclusive.TODO: Document this in AVM at aionnetwork/AVM#408 need to update this section.
Authorization
The mechanism for authorizing accounts is a self-contained system. And an owner does not implicitly authorize itself.
Alternative considered: make owner implicitly authorize itself and prevent owner from deauthorizing self. This additional specification would provide no purpose because transfers are specified being permitted from the owner to themself (subject to application-specific restrictions) regardless of whether they authorize themself.
Events
Events must be fired for each minted, burned and transferred token. The events were designed as a database to lookup historical information about tokens. This is why batch token transfers will emit each token separately.
Token identifiers are padded as signed integers to 32 bytes. This is because Aion will mutate log topics to 32 bytes. Aion behavior makes negative
BigInteger
s smaller than 32 bytes indistinguishable from similar positive integers which are similar (MOD 2^bits).TODO: Add citation, see aionnetwork/AVM#413
Risks & Assumptions
Test Cases
Implementations
Dependencies
References
Standards and API
Vendor issues
Best practices
Copyright
to https://creativecommons.org/publicdomain/zero/1.0/
The text was updated successfully, but these errors were encountered: