We’re proposing a new standard for Linkdrops! Huge thanks to Ken Miyachi for helping out with this standard!
Summary
A standard interface for linkdrops that support $NEAR, fungible tokens, non-fungible tokens, and is extensible for linkdrops of any type.
Motivation
Linkdrops are an extremely powerful tool that enable seamless onboarding and instant crypto experiences with the click of a link. The original near-linkdrop contract provides a minimal interface allowing users to embed $NEAR within an access key and create a simple Web2 style link that can then be used as a means of onboarding. This simple $NEAR linkdrop is not enough as many artists, developers, event coordinators, and applications want to drop more digital assets such as NFTs, FTs, tickets etc.
As linkdrop implementations start to push the boundaries of what’s possible, new data structures, methods, and interfaces are being developed. There needs to be a standard data model and interface put into place to ensure assets can be claimed independent of the contract they came from. If not, integrating any application with linkdrops will require customized solutions, which would become cumbersome for the developer and deteriorate the user onboarding experience. The linkdrop standard addresses these issues by providing a simple and extensible standard data model and interface.
Rationale and alternatives
- Why is this design the best in the space of possible designs?
This design allows for flexibility and extensibility of the standard while providing a set of criteria that cover the majority of current linkdrop use cases. The design was heavily inspired by current, functional NEPs such as the Fungible Token and Non-Fungible Token standards.
- What other designs have been considered and what is the rationale for not choosing them?
A generic data struct that all drop types needed to inherit from. This struct contained a name and some metadata in the form of stringified JSON. This made it easily extensible for any new types down the road.
The rationale for not choosing this design was both simplicity and flexibility. Having one data struct required keys to be of one type only when in reality, they can be many at once. In addition, having a generic, open-ended metadata field could lead to many interpretations and different designs.
We chose to use a KeyInfo struct that can be easily extensible and can cover all use-cases by having optional vectors of different data types. The proposed standard is simple, supports drops with multiple assets, and is backwards compatible with all previous linkdrops, and can be extended very easily.
- What is the impact of not doing this?
The impact of not doing this is creating a fragmented ecosystem of linkdrops, increasing the friction for user onboarding. Linkdrop claim pages (e.g. wallet providers) would have to implement custom integrations for every linkdrop provider platform. Inherently this would lead to a bad user experience when new users are onboarding and interacting with linkdrops in general.
Specification
/// Information about a specific public key.
pub struct KeyInfo {
/// yoctoNEAR$ amount that will be sent to the claiming account (either new or existing)
// when the key is successfully used.
pub balance: U128,
/// If using the NFT standard extension, a set of NFTData can be linked to the public key
/// indicating that all those assets will be sent to the claiming account (either new or
/// existing) when the key is successfully used.
pub nft_data: Option<Vec<NFTData>>,
/// If using the FT standard extension, a set of FTData can be linked to the public key
/// indicating that all those assets will be sent to the claiming account (either new or
/// existing) when the key is successfully used.
pub ft_data: Option<Vec<FTData>>,
// ... other types can be introduced and the standard is easily extendable.
}
/// Data outlining a specific Non-Fungible Token that should be sent to the claiming account /// (either new or existing) when a key is successfully used.
pub struct NFTData {
/// the id of the token to transfer
pub token_id: string,
/// The valid NEAR account indicating the Non-Fungible Token contract.
pub contract_id: string
}
/// Data outlining Fungible Tokens that should be sent to the claiming account
/// (either new or existing) when a key is successfully used.
pub struct FTData {
/// The number of tokens to transfer, wrapped in quotes and treated
/// like a string, although the number will be stored as an unsigned integer
/// with 128 bits.
pub amount: string,
/// The valid NEAR account indicating the Fungible Token contract.
pub contract_id: string
}
/****************/
/* VIEW METHODS */
/****************/
// Returns the $yoctoNEAR amount associated with a given public key
// Panics if the key does not exist
pub fn get_key_balance(&self, key: PublicKey) -> U128
// Returns the KeyInfo associated with a given public key
// Panics if the key does not exist
pub fn get_key_information(&self, key: PublicKey) -> KeyInfo
/******************/
/* CHANGE METHODS */
/******************/
// Transfer all assets linked to the signer’s public key to an *existing* NEAR account. If the transfer
// fails for whatever reason, it is up to the smart contract developer to choose what should
// happen. For example, the contract can choose to keep the assets or send them back to the
// original linkdrop creator.
//
// Requirements:
// * The predecessor account *MUST* be the current contract ID.
// * The assets being sent *MUST* be associated with the signer’s public key.
// * The assets *MUST* be sent to the `account_id` passed in.
//
// Arguments:
// * `account_id` the account that should receive the linkdrop assets.
pub fn claim(account_id: string) -> Promise
// Creates a new NEAR account and transfers all assets linked to the signer’s public key to the
// *newly created account*. If the transfer fails for whatever reason, it is up to the smart contract
// developer to choose what should happen. For example, the contract can choose to keep the
// assets or send them back to the original linkdrop creator.
//
// Requirements
// * The predecessor account *MUST* be the current contract ID.
// * The assets being sent *MUST* be associated with the signer’s public key.
// * The assets *MUST* be sent to the `new_account_id` passed in.
// * The newly created account *MUST* have a new access key added to its account (either
// full or limited access) in the same receipt that the account was created in.
//
// Arguments
// * `new_account_id`: the valid NEAR account which is being created and should
// receive the linkdrop assets
// * `new_public_key`: the valid public key that should be used for the access key added to
// the newly created account.
pub fn create_account_and_claim(new_account_id: string, new_public_key: string) -> Promise
Reference Implementation
Future Possibilities
- Function call data types
- Optional configurations added to KeyInfo which can include multi-usekeys, time-based claiming etc…
- Standard process for how links connect to claim pages (i.e a standardized URL such as an app’s
baseUrl/contractId=[LINKDROP_CONTRACT]&secretKey=[SECRET_KEY]
- Standard for deleting keys and refunding assets.
Copyright
Copyright and related rights waived via CC0.