BitSong
Search
K

Fan Tokens

What are Fan Tokens?

Fan tokens are a brand new phenomenon already making waves in the sports sector. A fan token is a cryptocurrency issued for the benefit of star performers — whether that’s a world-famous rock band, or an up-and-coming solo talent — and their fans.
Why does the music industry need fan tokens? Because they allow any act or artist to create their own economy, generating new ways to monetise their music and brand, and providing a unique and innovative channel to engage with fans.
BitSong’s Fan Token module allows artists to mint their own branded tokens for any purpose. But here are a few ways that they can be used:
Create a loyalty program allowing fan token holders privileged access to exclusive content such as unreleased materials or behind-the-scenes interviews
Crowdfund a tour or studio album and revenue-sharing with token holders
Give fans the opportunity to vote, for example, on the song lineup for a gig or on the cities for an upcoming tour
Accept fan tokens as payment for NFTs
The BitSong Fan Token module enables any artist to start minting their own fan tokens and list them within a few minutes, for low fees. BitSong also stands apart from other fan token platforms by offering the opportunity to link BitSong Fan Tokens to social profiles, such as Twitter.

Abstract

This document specifies the fantoken module of the BitSong chain.
The fantoken module enables the BitSong chain to support fan tokens, allowing actors in the content creation industry to create their economy. In this sense, they can generate new ways to monetize their music and brand and provide a unique and innovative channel to engage with fans. Thanks to this module, players from the content creation universe can start minting their fan tokens (which are fungible tokens) and listing them within a few minutes for low fees.

An example: Fan tokens in the music Industry

In the music industry, for example, fan tokens enable to empower a lot of different scenarios. For instance, it is possible to use them to crowdfund a tour or an album, or even to access exclusive content. The potential of such a system is very massive and, with these few examples, you can imagine what a contribution this tool can make to a world teeming with content creators.

Fan tokens in BitSong

Based on the concept of the ERC-20 Standard, BitSong fan tokens enable the user to a new way of value exchanging. Here, through tokens issued by a particular entity, the fans can deeply interact with their influencers or idols.
We can identify each fan token through its denom. Moreover, even if its denom allow the global identification of the token, each fan token is also equipped with a name and a symbol, which helps in its recognition. The name and the symbol of a fan token, together with a uri and an authority (i.e., the address of the wallet which is able to manage those data) are part of the metadata of the fan token.
More specifically:
  • denom is calculated by the tendermint crypto hash function through the block height of the transaction, the first minter, the symbol, and the name. For this reason, it is unique;
  • symbol is defined by the user and can be any string matching the pattern ^[a-z0-9]{1,64}$, so any lowercase string containing letters and digits with a length between 1 and 64 characters. It cannot be empty;
  • name, on the other hand, is also defined by the user but it can be any string containing max 128 characters. It can also be empty.
Finally, thanks to the fantoken module, users on BitSong can:
  • manage fan tokens, issuing, minting, burning, and transferring them;
  • build applications that use the fan tokens API to create completely new and custom artists' economies.
Features that may be added in the future are described in Future Improvements.

Concepts

Conventions

By looking at numbers, we separate the decimals by point and the thousands by comma. For instance, the number one thousand two hundred thirty-four and fifty-six hundredths, is written as:
formula

Fan token

Fan tokens, conceptually based on the ERC-20 Standard, are fungible tokens issued for fan communities. They borns to create new connections between fans and any content creator, like star performers, actors, designers, musicians, photographers, writers, models, influencers, etc. They enable the growth of a private and (most importantly) custom economy creating new channels for fans' engagement. Fan tokens have enormous potential. By using them, you can build myriad applications allowing fans a deeper interaction in the artistic life of their top performers.
To provide you with some examples, you can think that it is possible to use them for creating loyalty programs to provide privileged access to exclusive content. To allow your fan to crowdfund a tour or studio album and share part of the revenue with your fans. To enable your fans with the opportunity to vote on the cities for an upcoming tour. Or even to accept fan tokens as payment for NFTs.
In the design of the fan token functionalities, big part of the reasonings were based on the OpenZeppelin standard. For example, the concept of burning the tokens lowering the totalSupply directly derives from the standard documentation.
A fan token is characterized by:
Attribute
Type
Description
denom
string
It is an hash calculated on the first Minter, the Symbol, the Name and the Block Height of the issuing transaction of the fan token. It is the hash identifying the fan token and is used to prevent the creation of identical tokens. Moreover, to fastly identify a fan token from its denom, it starts with the prefix ft.
max_supply
sdk.Int
It is chosen once by the user. It is the maximum supply value of mintable tokens from its definition. It is expressed in micro unit (
formula
). For this reason, to indicate a maximum supply of
formula
tokens, this value must be equal to
formula
.
Minter
sdk.AccAddress
It is the address of the minter for the fan token. It can be changed to trasfer the minting ability of the token during the time.
metadata
Metadata
It is generated once and it is made up of Name, Symbol, URI and Authority (i.e., is the address of the wallet which is able to perform edits on the URI). More specifically, the URI contains a link to a resource with a set of information linked to the fan token.
Metadata are characterized by:
Attribute
Type
Description
name
string
It is chosen once by the user. It should correspond to the long name the user want to associate to the symbol (e.g., Dollar, Euro, BitSong). It can also be empty and its max length is of 128 characters.
symbol
string
It is chosen once by the user and can be any string matching the pattern ^[a-z0-9]{1,64}$, i.e., any lowercase string containing letters and digits with a length between 1 and 64 characters. It should follow the ISO standard for the alphabetic code (e.g., USD, EUR, BTSG, etc.).
uri
string
It is a link to a resource which contains a set of information linked to the fan token. It can also be empty and its max length is of 512 characters.
authority
sdk.AccAddress
It is the address of the authority for the fan token metadata managment. It can be changed to trasfer the ability of changing the metadata the token during the time.

Lifecycle of a fan token

It is possible to entirely represent the lifecycle of a fan token through Finite State Machine (FSM) diagrams. We will present two representations:
  • the first refers to the fan token object. We can compare such a definition with that of currency (e.g., Euro, Dollar, BitSong);
  • the second, instead, is referred to the lifecycle of the fan token instance. Such definition is comparable with that of coin/money (e.g., the specific 1 Euro coin you could have in your pocket at a particular moment in time).
We can describe the lifecycle of a fan token object through two states.
Referring to the figure above, as detailed in the documentation, to "create" the fan token, we need to issue it. This operation leads to the birth of the object and thus to its first state, state 1. Here, the token is related to a minter, who is able to mint the token to different wallets, and an authority, that is responsible for managing the metadata. It is important to recall that some operations are reversible, while some others are not. For example, reaching the max-supply through minting operations, can be reverted by burning tokens. While, for example, the selection of an empty address for the minter (which strictly means disable minting operations) is a irreversible operation.
Referring to the lifecycle of a fan token instance, it is possible to identify two states.
Concerning to the figure above, when the fan token object is issued, we can mint it. Minting leads to the birth of a new instance, moving the fan token instance to state 1. In this state, the token can be:
  • traded, which produces the changing of the owner of the instance, without modifying the landing state. To make it clearer, it can be considered as the simple exchange of money between two users. This does not modify the landing state;
  • burned, which produces a state change to the state 2, where the authority cannot operate on the fan token instance anymore.

Uniqueness of the denom

The denom is calculated on first Minter, Symbol, Name and Block Height of the issuing transaction of the fan token.
func GetFantokenDenom(height int64, minter sdk.AccAddress, symbol, name string) string {
bz := []byte(fmt.Sprintf("%d%s%s%s", height, minter.String(), symbol, name))
return "ft" + tmcrypto.AddressHash(bz).String()
}
The denom of every fan token starts with the prefix ft. Follows a hash of Block Height, first Minter, Symbol and Name of the fan token. This denom is used as base denom for the fan token, and, for this reason, it should be unique. In this sense, since the hash depends both on the first Minter and the Block Height, multiple fan tokens with the same name and symbol can co-exist even created by the same address but they must be created from transactions in different blocks.

State

The fantoken module keeps track of parameters and fan tokens.
Params: types.Params
FanTokens: []types.FanToken

Params

In the state definition, we can find the Params. This section corresponds to a module-wide configuration structure that stores system parameters. In particular, it defines the overall fantoken module functioning and contains the issueFee, mintFee and burnFee for the fan token. Such an implementation allows governance to decide the issue fee, but also the mint and burn fees the users have to pay to perform these operations with the tokens, in an arbitrary way - since proposals can modify it.
type Params struct {
IssueFee sdk.Coin
MintFee sdk.Coin
BurnFee sdk.Coin
}

Fantoken

The state contains a list of Fantokens. They are fan tokens (fungible tokens deriving by the ERC-20 Standard), and their state information is:
  • Denom, that corresponds to the identifier of the fan token. It is a string, automatically calculated on the first Minter, Symbol, Name and Block Height of the issuing transaction of the fan token as explained in concepts, and cannot change for the whole life of the token;
  • MaxSupply, that represents the upper limit for the total supply of the tokens. More specifically, it is an integer number, expressed in micro unit (
    formula
    ) as explained in concepts, that cannot change for the whole life of the token and which corresponds to the maximum number the supply can reach in any moment;
  • Minter, which corresponds to the address of the current minter for the token. It is an address and can change during the token lifecycle thanks to the minting ability transfer. When the minter address is set to an empty value, the token can be minted no more;
  • MetaData, which contains metadata for the fan token and is made up of the Name, the Symbol, a URI and an Authority as described in concepts.
More specifically, the metadata can change during the life of the token according to:
  • URI can be changed by the authority. It can be changed until when the authority is available;
  • Authority which can be transferred by the current authority until when the authority itself is not set to an empty value.
type FanToken struct {
Denom string
MaxSupply sdk.Int
Minter string
MetaData types.Metadata
}
type Metadata struct {
Name string
Symbol string
URI string
Authority string
}

Messages

Messages (msgs) are objects that trigger state transitions. Messages are wrapped in transactions (txs) that clients submit to the network. The BitSong SDK wraps and unwraps fantoken module messages from transactions.

MsgIssue

The MsgIssue message is used to issue a new fan token. It takes as input Symbol, Name, MaxSupply (expressed in micro unit (
formula
) as explained in concepts), Authority (i.e., the address of the wallet which is able to modify the metadata of the fan token), URI (which is a link to the fan token metadata) and the Minter (i.e., the address of the wallet which is able to mint the fan token). Thanks to these values, the module can verify if the Authority and the Minter are valid addresses for the issue of a new token (they are not a blocked addresses or module accounts) and also verifies the values for the name (which can be any strings with max 128 characters, even the empty one), the symbol (that must match the regex ^[a-z0-9]{1,64}$) and the uri (which can be any strings with less than 513 characters, even the empty one). At this point, it proceeds with token issuing and emitting of corresponding events. More specifically, the module deduct the issuing fee from the minter wallet, calculates the denom, generates the metadata, and finally creates the fan token. At this point, an EventIssue event is emitted.
type MsgIssue struct {
Symbol string
Name string
MaxSupply sdk.Int
Authority string
URI string
Minter string
}

MsgDisableMint

The MsgDisableMint message is used to irreversibly disable the minting ability for an existing fan token. It takes as input Denom and Minter (described in fan token definition). Thanks to these values, the module can verify whether the modifications are lawful (i.e., requested by the Minter and in accord with the state transition definition). The message permits to change the "mintability" of the fan token. In particular, at the issuing, the fan token can be minted (in fact the Minter address is a value different from an empty one). Later on, during the lifecycle of the fan token, the minter can disable the possibility to mint new tokens (check the relative docs for more details). In such a scenario, it is possible to disable the mintability, by set an empty value as the address for the new minter) and, this operation, causes the MaxSupply of the token to be updated at the current value of the supply. At this point, an EventDisableMint event is emitted.
type MsgDisableMint struct {
Denom string
Minter string
}

MsgMint

The MsgMint message is used to mint an existing fan token. It takes as input Recipient, Coin, and Minter (all described in fan token definition except the Coin, which is an object made up of the denom of the fan token to mint and its quantity, expressed in micro unit). In such a message, the Recipient is not required and its default value is the same of Minter. Thanks to these values, the module can verify whether the minting operation is lawful (i.e., requested: by the minter, on a mintable fan token, and for a quantity that allow to do not overcome the maximum supply), recalling that only the minter for of the fan token can mint the token to any specified account. At this point, the token is minted, the supply is increased, the coins are sent to the recipient, the module deduct the mint fee from the minter wallet and an EventMint event is emitted.
type MsgMint struct {
Recipient string
Coin sdk.Coin
Minter string
}

MsgBurn

The MsgBurn message is used to burn fan token. It takes as input Coin, and Sender (as above, the Coin is an object made up of the denom of the fan token to burn and its quantity, expressed in micro unit, while Sender must be equal to the user who want to burn the tokens). The module can verify whether the burning operation is lawful (i.e., the sender has a sufficient amount of token, in other words check if sender balance > amount to burn). At this point, the token is burned, the supply is lowered, the module deduct the burn fee from the owner wallet and an EventBurn event is emitted. In such a way, that specific token ends its lifecycle, as shown in the relative docs.
type MsgBurn struct {
Coin sdk.Coin
Sender string
}

MsgSetAuthority

The MsgSetAuthority message is used to transfer or disable the ability to change the metadata of a fan token. It takes as input Denom, oldAuthority, and newAuthority (Denom is described in fan token definition, old and new Authorities are respectively the actual and the new addresses of the wallet who are able to change the metadata of the token). When the newAuthority is an empty address, the capability to change the metadata is irreversibly disabled. The module can verify whether the operation is lawful (i.e., the requesting account is actually the authority for the fan token, the fan token metadata can be changed and the destination account is neither blocked nor a module account). At this point, if the newAuthority is a not empty address, it becomes the new token authority. On the other hand, the fan token metadata cannot be changed anymore. Anyway, an EventSetAuthority event is emitted. This operation enable the authority transfer transition described in the lifecycle of a fan token.
type MsgTransferAuthority struct {
Denom string
oldAuthority string
newAuthority string
}

MsgSetMinter

The MsgSetMinter message is used to transfer the ability to mint a fan token. It takes as input Denom, oldMinter, and newMinter (Denom is described in fan token definition, old and new Minters are respectively the actual and the new addresses of the wallet who are able to mint the token). When the newMinter is an empty address, it works as the MsgDisableMint. The module can verify whether the operation is lawful (i.e., the requesting account is actually the minter for the fan token, the fan token can be minted and the destination account is neither blocked nor a module account). At this point, if the newMinter is a not empty address, it becomes the new token minter. On the other hand, the fan token cannot be minted anymore. Anyway, an EventSetMinter event is emitted. This operation enable the minter transfer transition described in the lifecycle of a fan token.
type MsgSetMinter struct {
Denom string
oldMinter string
newMinter string
}

MsgSetUri

The MsgSetMinter message is used to modify the URI in the fan token metadata. It takes as input Denom, new URI, and Authority (Denom and URI are described in fan token definition, Authority is the actual address of the wallet who is able to modify the fan token metadata). The module can verify whether the operation is lawful (i.e., the requesting account is actually the authority for the fan token, the fan token metadata can be changed and the new uri is a valid one, as described in Fan Token parameters definition). At this point, an EventSetUri event is emitted.
type MsgSetUri struct {
Denom string
URI string
Authority string
}

Events

The fantoken module emits the following events:

EventIssue

Type
Attribute Key
Attribute Value
message
action
/bitsong.fantoken.v1beta1.MsgIssue
bitsong.fantoken.v1beta1.EventIssue
denom
{denom}

EventDisableMint

Type
Attribute Key
Attribute Value
message
action
/bitsong.fantoken.v1beta1.MsgDisableMint
bitsong.fantoken.v1beta1.EventDisableMint
denom
{denom}

EventMint

Type
Attribute Key
Attribute Value
message
action
/bitsong.fantoken.v1beta1.MsgMint
bitsong.fantoken.v1beta1.EventMint
recipient
{recipient}
bitsong.fantoken.v1beta1.EventMint
coin
{coin}

EventBurn

Type
Attribute Key
Attribute Value
message
action
/bitsong.fantoken.v1beta1.MsgBurn
bitsong.fantoken.v1beta1.EventBurn
sender
{sender}
bitsong.fantoken.v1beta1.EventBurn
coin
{coin}

EventSetAuthority

Type
Attribute Key
Attribute Value
message
action
/bitsong.fantoken.v1beta1.MsgSetAuthority
bitsong.fantoken.v1beta1.EventTransferAuthority
denom
{denom}
bitsong.fantoken.v1beta1.EventTransferAuthority
old_authority
{old_authority}
bitsong.fantoken.v1beta1.EventTransferAuthority
new_authority
{new_authority}

EventSetMinter

Type
Attribute Key
Attribute Value
message
action
/bitsong.fantoken.v1beta1.MsgSetMinter
bitsong.fantoken.v1beta1.EventTransferMinter
denom
{denom}
bitsong.fantoken.v1beta1.EventTransferMinter
old_minter
{old_minter}
bitsong.fantoken.v1beta1.EventTransferMinter
new_authority
{new_minter}

EventSetUri

Type
Attribute Key
Attribute Value
message
action
/bitsong.fantoken.v1beta1.MsgSetUri
bitsong.fantoken.v1beta1.EventSetUri
denom
denom}

Parameters

Fantoken module parameters.
Key
Type
Value
IssueFee
sdk.Coin
{"denom": "ubtsg", "amount": "1000000"}
MintFee
sdk.Coin
{"denom": "ubtsg", "amount": "0"}
BurnFee
sdk.Coin
{"denom": "ubtsg", "amount": "0"}

Client

Transactions

The transactions commands allow users to issue, mint, burn, disable minting, transfer minting and editing capabilities for fan tokens.
bitsongd tx fantoken --help

issue

bitsongd tx fantoken issue \
--name "fantoken name" \
--symbol "bitangel" \
--max-supply 100000000000 \
--uri "ipfs://...." \
--from <key-name> -b block --chain-id <chain-id> --fees <fee>

mint

bitsongd tx fantoken mint [amount][denom] \
--recipient <address> \
--from <key-name> -b block --chain-id <chain-id> --fees <fee>

burn

bitsongd tx fantoken burn [amount][denom] \
--from <key-name> -b block --chain-id <chain-id> --fees <fee>

set-authority

bitsongd tx fantoken set-authority [denom] \
--new-authority <address> \
--from <key-name> -b block --chain-id <chain-id> --fees <fee>

set-minter

bitsongd tx fantoken set-minter [denom] \
--new-minter <address> \
--from <key-name> -b block --chain-id <chain-id> --fees <fee>

set-uri

bitsongd tx fantoken set-uri [denom] \
--uri <uri> \
--from <key-name> -b block --chain-id <chain-id> --fees <fee>

disable-mint

bitsongd tx fantoken disable-mint [denom] \
--from <key-name> -b block --chain-id <chain-id> --fees <fee>

Query

The query commands allow users to query the fantoken module.
bitsongd q fantoken --help

denom

bitsongd q fantoken denom <denom>

authority

bitsongd q fantoken authority <address>

params

bitsongd q fantoken params