aptos-foundation / AIPs

Aptos Improvement Proposals (AIPs)
https://governance.aptosfoundation.org/
126 stars 98 forks source link

[AIP-5][Discussion] Soulbound and Freezing Token Standard #18

Closed JacobADevore closed 1 year ago

JacobADevore commented 1 year ago

[AIP-5] Soulbound and Freezing Token Standard

This standard allows for the existence of soulbound NFTs and freezing tokens.

Motivation

Soulbound tokens have enormous potential in a wide variety of applications. However, with no standard, soulbound tokens are incompatible with the Aptos-Token standard. Consensus on a common standard is required to allow for broader ecosystem adoption, as well as to make it easier for application developers to build expressive applications on top of the standard.

This AIP (Aptos Improvement Proposal) envisions soulbound tokens as non-transferable NFTs that will unlock primitives such as robust proof of attendance, credentials, distributed governance rights, and much more. However, soulbound tokens must be distinguishable from Aptos-Tokens to provide this utility.

Benefits:

Requirements

Approach

Extend property map to have framework reserved keys

Reserve all keys with “##” for framework usage.

When adding keys to property_map, we need to check if the key starts with “##” and disallow adding or creating property_map with these keys.

We add a token package friend function for adding framework-reserved control flags

// This function should only be called by framework modules
public(friend) fun add_framework_reserved_control_flag(map: &mut PropertyMap, key: String, value: PropertyValue)

Note: after this change, the property_map will become a dedicated data structure for the token package.

Annotate the token as soul bound

// Mint soulbond tokens specifically
public entry create_mint_soulbound_token(creator: &signer, owner: address, collection_name: String, token_name: String){
    // Create token_data
    let token_data_id = create_token_data(...);
    // Mint a token from token_data_id
    let token = mint_token(token_data_id);

    // Offer token to owner
    token_transfers::offer(creator, owner, token_id, ..);
    // Annotate the token property #freezing_type to 0
    add_framework_reserved_control_flag(token.token_properties, "“##freezing_type", 1);
}

public fun is_soulbound_token(token_id: TokenId): bool {
    // Check the token properties
}

public fun withdraw_token(account: &signer, id: TokenId, amount: u64){
    let token_data_id = id.token_data_id;
    // Check the token's properties and validate if the ##freezing_type value is set
    ...
}

Extension

We can extend the approach to support general frozen tokens to token stores. For example, the token owner or creator wants to freeze the token to their token store after an expiration time. We can use ##freezing_type = 2 for the time-based freezing. we can introduce another system-reserved control flag to specify the timestamp ##freezing_expiration_time.

public fun freeze_token(owner: &signer, token_id: TokenId, expiration_time: u64){
    // annotate the token with two properties above
}

public withdraw(...){
    //check if the token is frozen and the expiration time.
}

Other Alternatives

Suggested Implementation Timeline

To be determined.

References

--

Special thanks to Bo Wu.

movekevin commented 1 year ago

This is a really nice AIP writeup! I have one question about how soul bound tokens are supposed to work: When do they become soul bound? Is it when the tokens are minted?

JacobADevore commented 1 year ago

This is a really nice AIP writeup! I have one question about how soul bound tokens are supposed to work: When do they become soul bound? Is it when the tokens are minted?

Thank you Kevin, I am currently working with @areshand on the exact implementation.

ghost commented 1 year ago

0x3::token is really gas heavy enough, why we should keep change that? I recommend an another approach: clone 0x3::token standard to be 0x3::soulbound_token, so you don't need do a verify for withdraw/deposit. https://github.com/aptos-foundation/AIPs/pull/16#issuecomment-1375266782

ghost commented 1 year ago

0x3::token is really gas heavy enough, why we should keep change that? I recommend an another approach: clone 0x3::token standard to be 0x3::soulbound_token, so you don't need do a verify for withdraw/deposit. #16 (comment)

by doing separate module, you dont need to verify is it soulbound token or normal token, further to reduce the gas fee down. then we could simply to remove transfer function on soulbound token.

alnoki commented 1 year ago

@JacobADevore I suggest renaming "Soulbound" to either "SignerBound" or "KeyBound" for the following reasons:

  1. Distances a useful blockchain primitive from quasi-religious nomenclature, which could prove exclusionary for individuals with (a)religious/philosophical attitudes that reject unfalsifiable metaphysical claims about souls or consider it blasphemous that blockchain tokens could be bound to a soul. Notably the notion of a soul has historically been abused, most frequently in the service of denying that certain classes of sentient beings lack them (slaves, women, heathens, non-human animals) such that these classes can be subjected to harmful treatment without reproach. Consider that GitHub has changed the default branch name from master to main to avoid references to similarly violent historical institutions.
  2. Clarifies that the token is indeed bound to a key/signer, not the individual person behind the signature, which will (a) avoid confusion in the instance that an account is compromised and (b) serves to increase a security-minded mindset around not losing a private key (as opposed to assuming that someone can "recover" their SingerBound token through appeal to a central Web2 authority, for instance).
  3. Avoids confusion that may arise with having a token affiliated with a multisignature wallet. Here, the term "KeyBound" may be more appropriate than "SignerBound", since there are multiple signers on a multisig wallet, though notably the account is itself treated as having a single conglomerate signature. Either option, however, provides more clarity than the initial name in this proposal, which raises the question of whose soul the token belongs to from the collection of signatories.
  4. Provides more appropriate description within the context of Aptos' key rotation schema, which can theoretically support the transfer of such a token from one person to another: here, someone just has to rotate their authentication key to someone else's public key. And actually, now that I think about it, I suspect that Aptos' key rotation schema might actually prohibit the kind of bound token originally put forth here. If I have some special token in my account, what is to stop someone from paying me paper fiat to rotate the authentication key for the account to a public key that they specify?

Understandably such a renaming may be met with some resistance given that the term "soulbound" has already achieved some amount of prominence, but it is still early enough to alter the trajectory of this norm into a more inclusive and contextually-meaningful term. To this end, I'd especially like to hear your thoughts on reason 1. Also, is it correct that the discussion in reason 4 raises a potentially-insuperable technical challenge?

davidiw commented 1 year ago

Take a look at proposed AIP-11 and 20. This moves to an object model that allows for seamless soul bound and other functionality without core modifications to the framework. Curious if it is advantageous to continue down this path or to focus on putting our energy behind those. https://github.com/aptos-foundation/AIPs/pull/92/files

davidiw commented 1 year ago

Closing out as this is addressed by TokenV2 / Token Objects / Digital Assets.