Create a Variable-Cap Asset
Introduction
This tutorial illustrates how to create a variable-cap, fungible asset. No units of the asset exist when the asset is initialized, but more units of the asset may be minted. On asset creation, we specify which sets of addresses may mint more units.
You may be wondering why we specify sets of addresses that can mint more units of the asset rather than a single address. Here's why:
- Security: if only one address can mint more of the asset, and the private key for that address is lost, no more units can ever be minted. Similarly, if only one address can mint more of the asset, nothing stops the holder of that address from unilaterally minting as much as they want.
- Flexibility: it’s nice to be able to encode logic like, "Alice can unilaterally mint more units of this asset, or 2 of Dinesh, Ellin, and Jamie can together mint more."
Suppose that we want to issue an asset that represents shares of a corporation. No shares exist to start with, but more shares may be created later. Let’s create such an asset.
Requirements
You've completed Run an Avalanche Node and are familiar with Avalanche's architecture.
Create the Asset
Our asset will exist on the X-Chain, so to create our asset we’ll call avm.createVariableCapAsset
, which is a method of the X-Chain’s API.
The signature for this method is:
avm.createVariableCapAsset({
name: string,
symbol: string,
denomination: int,
minterSets []{
minters: []string,
threshold: int
},
from: []string,
changeAddr: string,
username: string,
password: string
}) ->
{
assetID: string,
changeAddr: string,
}
Parameters
name
is a human-readable name for our asset. Not necessarily unique. Between 0 and 128 characters.symbol
is a shorthand symbol for this asset. Between 0 and 4 characters. Not necessarily unique. May be omitted.denomination
determines how balances of this asset are displayed by user interfaces. If denomination is 0, 100 units of this asset are displayed as 100. If denomination is 1, 100 units of this asset are displayed as 10.0. If denomination is 2, 100 units of this asset are displays as .100, etc.minterSets
is a list where each element specifies thatthreshold
of the addresses inminters
may together mint more of the asset by signing a minting transaction.- Performing a transaction on the X-Chain requires a transaction fee paid in AVAX.
username
andpassword
denote the user paying the fee. from
are the addresses that you want to use for this operation. If omitted, uses any of your addresses as needed.changeAddr
is the address any change will be sent to. If omitted, change is sent to one of the addresses controlled by the user.
Response
assetID
is the ID of the new asset.changeAddr
in the result is the address where any change was sent.
Later in this example, we’ll mint more shares, so be sure to replace at least 2 addresses in the second minter set with addresses your user controls.
curl -X POST --data '{
"jsonrpc":"2.0",
"id" : 1,
"method" :"avm.createVariableCapAsset",
"params" :{
"name":"Corp. Shares",
"symbol":"CS",
"minterSets":[
{
"minters": [
"X-avax1ghstjukrtw8935lryqtnh643xe9a94u3tc75c7"
],
"threshold": 1
},
{
"minters": [
"X-avax1k4nr26c80jaquzm9369j5a4shmwcjn0vmemcjz",
"X-avax1yell3e4nln0m39cfpdhgqprsd87jkh4qnakklx",
"X-avax1ztkzsrjnkn0cek5ryvhqswdtcg23nhge3nnr5e"
],
"threshold": 2
}
],
"from":["X-avax1s65kep4smpr9cnf6uh9cuuud4ndm2z4jguj3gp"],
"changeAddr":"X-avax1turszjwn05lflpewurw96rfrd3h6x8flgs5uf8",
"username":"USERNAME GOES HERE",
"password":"PASSWORD GOES HERE"
}
}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/X
The response should look like this:
{
"jsonrpc":"2.0",
"id" :1,
"result" :{
"assetID":"i1EqsthjiFTxunrj8WD2xFSrQ5p2siEKQacmCCB5qBFVqfSL2",
"changeAddr":"X-avax1turszjwn05lflpewurw96rfrd3h6x8flgs5uf8"
}
}
Mint the Asset
Right now 0 shares exist. Let’s mint 10M shares.
Create the Unsigned Transaction
We’ll use avm.mint
to mint the shares.
amount
is the number of shares that will be created.assetID
is the ID of the asset we’re creating more of.to
is the address that will receive the newly minted shares. Replaceto
with an address your user controls so that later you’ll be able to send some of the newly minted shares.username
must be a user that holds keys giving it permission to mint more of this asset. That is, it controls at least threshold keys for one of the minter sets we specified above.
curl -X POST --data '{
"jsonrpc":"2.0",
"id" : 1,
"method" :"avm.mint",
"params" :{
"amount":10000000,
"assetID":"i1EqsthjiFTxunrj8WD2xFSrQ5p2siEKQacmCCB5qBFVqfSL2",
"to":"X-avax1a202a8pu5w4vnerwzp84j68yknm6lf47drfsdv",
"username":"USERNAME GOES HERE",
"password":"PASSWORD GOES HERE"
}
}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/X
The response contains the transaction’s ID:
{
"jsonrpc":"2.0",
"id" :1,
"result" :{
"txID":"E1gqPbkziu8AutqccRa9ioPWyEF3Vd7eMjDJ3UshjQPpLoREZ",
"changeAddr": "X-avax1turszjwn05lflpewurw96rfrd3h6x8flgs5uf8"
}
}
We can check the status of the transaction we’ve just sent to the network using avm.getTxStatus
:
curl -X POST --data '{
"jsonrpc":"2.0",
"id" : 1,
"method" :"avm.getTxStatus",
"params" :{
"txID":"E1gqPbkziu8AutqccRa9ioPWyEF3Vd7eMjDJ3UshjQPpLoREZ"
}
}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/X
This should give:
{
"jsonrpc": "2.0",
"result": {
"status": "Accepted"
},
"id": 1
}
Trade the Asset
Check a Balance
All 10M shares are controlled by the to
address we specified in mint
. To verify this, we’ll use avm.getBalance
:
curl -X POST --data '{
"jsonrpc":"2.0",
"id" :1,
"method" :"avm.getBalance",
"params" :{
"address":"X-avax1a202a8pu5w4vnerwzp84j68yknm6lf47drfsdv",
"assetID":"i1EqsthjiFTxunrj8WD2xFSrQ5p2siEKQacmCCB5qBFVqfSL2"
}
}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/X
The response confirms that our asset creation was successful and that the expected address holds all 10,000,000 shares:
{
"jsonrpc":"2.0",
"id" :1,
"result" :{
"balance":10000000
}
}
Send the Asset
Let’s send 100 shares to another address by using avm.send
. To do so:
curl -X POST --data '{
"jsonrpc":"2.0",
"id" :1,
"method" :"avm.send",
"params" :{
"username":"USERNAME GOES HERE",
"password":"PASSWORD GOES HERE",
"assetID" :"i1EqsthjiFTxunrj8WD2xFSrQ5p2siEKQacmCCB5qBFVqfSL2",
"amount" :100,
"to" :"X-avax1qwnlpknmdkkl22rhmad0dcn80wfasp2y3yg3x0"
}
}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/X
Let’s check the balances of the to
address:
curl -X POST --data '{
"jsonrpc":"2.0",
"id" :1,
"method" :"avm.getBalance",
"params" :{
"address":"X-avax1qwnlpknmdkkl22rhmad0dcn80wfasp2y3yg3x0",
"assetID":"i1EqsthjiFTxunrj8WD2xFSrQ5p2siEKQacmCCB5qBFVqfSL2"
}
}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/X
The response should be:
{
"jsonrpc":"2.0",
"id" :1,
"result" :{
"balance":100
}
}
Wrapping up
In this tutorial, we:
- Used
createVariableCapAsset
to create a variable-cap asset that represents shares. - Used
mint
to mint more units of an asset. - Used
getBalance
to check address balances. - Used
send
to transfer shares.