Skip to content

Sample Code for Token Contract

TW edited this page Feb 19, 2021 · 1 revision

Token Contract

Using the VSYS Python API Wrapper pyvsystems

To generate and broadcast transactions, we can use pyvsystems to test contract functionalities on vsys chain.

Install pyvsystems

pyvsystems can be installed by first cloning the github repository

git clone https://github.com/virtualeconomy/pyvsystems.git

Then using pip, we can install the repository as a package

pip3 install pyvsystems/.

Then we can simply import pyvsystems in your own workplace

 

Register a Token contract

Import package pyvystems

import pyvsystems as pv
from pyvsystems import Account
from pyvsystems.contract_helper import *

Initialize API connection

To register a VSYS contract on chain, we must first initialize API parameters to a full node.

# Initialize API connection. API key is needed if you intend to interact with the node's database.
custom_wrapper = pv.create_api_wrapper("<your_node_address>", api_key="<your_node_api_key (optional)>")
# chain = pv.Chain(chain_name='mainnet', chain_id='M', address_version=5, api_wrapper=custom_wrapper)
chain = pv.Chain(chain_name='testnet', chain_id='T', address_version=5, api_wrapper=custom_wrapper)
sender = Account(chain=chain, seed="<your_sender_seed>")

VSYS contracts are defined by an encoded byte string that contains the information of the contract functions. We can get this information by the use of the contract helper classes.

# Contract object to be registered
token_without_split_contract_helper = TokenWithoutSplitContractHelper()
token_with_split_contract_helper = TokenWithSplitContractHelper()

token_contract_without_split_object = token_without_split_contract_helper.contract_object
token_contract_with_split_object = token_with_split_contract_helper.contract_object

Note that smart contracts in VSYS take in something called DataEntry, which specifies the value and type of the input. The functions in contracts have specific types of inputs, and the types must match in order to utilise the contract.

When we register a token contract, the availability of the split function depends on the encoded byte string we use. We must then specify the maximum supply, the unity and the description of the token.

Register a token contract with split

Token with split Contract ByteString:

3dPGAWbTw4srh5hmMiRUhHtcxmXXLUooKGAfnmz11j5NruyJpBzZpgvADMdZS7Mevy5MAHqFbfHYdfqaAe1JEpLWt1pJWLHZBV62zUhLGmVLXUP5UDvSs24jsBRHqZMC71ciE1uYtgydKxCoFJ3rAgsYqp7GDeTU2PXS5ygDmL6WXmbAYPS8jE4sfNUbJVwpvL1cTw4nnjnJvmLET8VmQybxFt415RemV3MFPeYZay5i5gMmyZa63bjzK1uMZAVWA9TpF5YQ1NTZjPaRPvQGYVY4kY9L4LFJvUG2bib1QaNh7wUAQnTzJfRYJoy1aegFGFZFnBGp9GugH4fHAY69vGmZQnhDw3jU45G9odFyXo3T5Ww4R5szegbjCUKdUGpXf9vY2cKEMJ7i8eCkFVG1dDFZeVov1KMjkVNV8rDBDYfcp3oSGNWQQvGSUT5iGUvDRN8phy1UpR3A9uMVebvjLnVzPx9RyqQ8HaXLM8vPhLuWLoh5hk1Zi1n9nwz55XvKDYjP6eeB55yK5vpg8xjaYDnw9bjYV7ZmS7LAsHvXfnwi8y2W6vk2hGvs4rtR1vNRZSQMPGRRSuwCRJL1yngH6uHWwm2ajWxc684jApuoLdyjZomfCtdpabSyU3kp9Lrn8zT8BVY332sJPQU6gTQi8ke9s9dBxCae4cfSQM6HhuBmFc5KKWHCVG4bm4KZRYbMtidw8ZZnjaAMtcGq7k3Se6GXaTxdS3GcuttB3VB7njypyzuqAcfCdYb9ht8Y1WuTCZ1aLsXsL6eydfk2WLJVrqYpbTk6AchV5gMAEopvc3qXvzrDCedjtNsDmA56Lh6PxrrKr8aV8Wzz8aMaQ88YsVBpE8J4cDkxzo31AojhzEGVBKLmpb3bjmsaw9VkpB6yL8ngYs8eJMSPdM289TSMaEmG4eHt1jezpHTKxkuB9cwqcvhGNLWuv8KXQkik5pRMXV67Qs2FvjpzeJ81z2hnVh1wCtsa6M6qAG1gsqLHa1AVMRzsowafC99uDexwWMBS2RqsZWZBXJcUiNVULjApSnoBREYfHYEpjJ152hnTYZCAwpZMWEkVdBQpZ3zk8gbfLxB4fWMfKgJJucbKPGp1K56u7P8MHQu9aNb9dEof2mwX8rTHjk8jSQ7kXVX4Mf1JqMRWWftkV3GmU1nqYhxRGu4FjDNAomwTr5epHpcMF6P5oiXcLWh5BFQVmGYKz129oizAyUJBsZdxr2WZEGDieLxUg8cve25g28oTuCVENST4z1ZsFAN9wTa1
Triggers Inputs Input Types Description
Init ("max", "unity", "tokenDescription") (amount, amount, short_text) Triggered when you register a Token With Split Contract
token_with_split_contract_helper = TokenWithSplitContractHelper()

token_contract_with_split_object = token_with_split_contract_helper.contract_object

register_token_contract_with_split_data_stack = token_with_split_contract_helper.register_data_stack_generator(<your_max_supply>, <your_unity>, "<your_description>")

sender.register_contract(token_contract_with_split_object, register_token_contract_with_split_data_stack)

Register a token contract without split

Token without split Contract ByteString:

3GQnJtxDQc3zFuUwXKbrev1TL7VGxk5XNZ7kUveKK6BsneC1zTSTRjgBTdDrksHtVMv6nwy9Wy6MHRgydAJgEegDmL4yx7tdNjdnU38b8FrCzFhA1aRNxhEC3ez7JCi3a5dgVPr93hS96XmSDnHYvyiCuL6dggahs2hKXjdz4SGgyiUUP4246xnELkjhuCF4KqRncUDcZyWQA8UrfNCNSt9MRKTj89sKsV1hbcGaTcX2qqqSU841HyokLcoQSgmaP3uBBMdgSYVtovPLEFmpXFMoHWXAxQZDaEtZcHPkrhJyG6CdTgkNLUQKWtQdYzjxCc9AsUGMJvWrxWMi6RQpcqYk3aszbEyAh4r4fcszHHAJg64ovDgMNUDnWQWJerm5CjvN76J2MVN6FqQkS9YrM3FoHFTj1weiRbtuTc3mCR4iMcu2eoxcGYRmUHxKiRoZcWnWMX2mzDw31SbvHqqRbF3t44kouJznTyJM6z1ruiyQW6LfFZuV6VxsKLX3KQ46SxNsaJoUpvaXmVj2hULoGKHpwPrTVzVpzKvYQJmz19vXeZiqQ2J3tVcSFH17ahSzwRkXYJ5HP655FHqTr6Vvt8pBt8N5vixJdYtfx7igfKX4aViHgWkreAqBK3trH4VGJ36e28RJP8Xrt6NYG2icsHsoERqHik7GdjPAmXpnffDL6P7NBfyKWtp9g9C289TDGUykS8CNiW9L4sbUabdrqsdkdPRjJHzzrb2gKTf2vB56rZmreTUbJ53KsvpZht5bixZ59VbCNZaHfZyprvzzhyTAudAmhp8Nrks7SV1wTySZdmfLyw7vsNmTEi3hmuPmYqExp4PoLPUwT4TYt2doYUX1ds3CesnRSjFqMhXnLmTgYXsAXvvT2E6PWTY5nPCycQv5pozvQuw1onFtGwY9n5s2VFjxS9W6FkCiqyyZAhCXP5o44wkmD5SVqyqoL5HmgNc8SJL7uMMMDDwecy7Sh9vvt3RXirH7F7bpUv3VsaepVGCHLfDp9GMG59ZiWK9Rmzf66e8Tw4unphu7gFNZuqeBk2YjCBj3i4eXbJvBEgCRB51FATRQY9JUzdMv9Mbkaq4DW69AgdqbES8aHeoax1UDDBi3raM8WpP2cKVEqoeeCGYM2vfN6zBAh7Tu3M4NcNFJmkNtd8Mpc2Md1kxRsusVzHiYxnsZjo
Triggers Inputs Input Types Description
Init ("max", "unity", "tokenDescription") (amount, amount, short_text) Triggered when you register a Token Without Split Contract
token_without_split_contract_helper = TokenWithoutSplitContractHelper()

token_contract_without_split_object = token_without_split_contract_helper.contract_object

register_token_contract_without_split_data_stack = token_without_split_contract_helper.register_data_stack_generator(<your_max_supply>, <your_unity>, "<your_description>")

sender.register_contract(token_contract_without_split_object, register_token_contract_without_split_data_stack)

 

Using Token Contract Functions

Once a token contract has been registered, its token can be used by executing the functions of the contract. Note that the function id of each function may be different depending on whether the contract allows split or doesn't.

With Split:

Executable Functions Function ID Inputs Input Types Description
Supersede 0 ("newIssuer") (address) Transfer issuing rights of Contract
Issue 1 ("amount") (amount) Issue new Tokens (only address with issuing rights can execute this function)
Destroy 2 ("amount") (amout) Destroy an amount of tokens (only address with issuing rights can execute this function)
Split 3 ("newUnity") (amount) Change the number each token can be split into (only address with issuing rights can execute this function)
Send 4 ("recipient", "amount") (address, amount) Send tokens
Transfer 5 ("sender", "recipient", "amount") (address, address, amount) Transfer tokens from sender to recipient
Deposit 6 ("sender", "contract", "amount") (address, contract_account, amount) Deposit tokens into another contract
Withdraw 7 ("contract", "recipient", "amount") (contract_account, address, amount) Withdraw tokens from another contract
TotalSupply 8 () () Currently not used
MaxSupply 9 () () Currently not used
BalanceOf 10 ("address") (address) Currently not used
GetIssuer 11 () () Currently not used

Without Split:

Executable Functions Function ID Inputs Input Types Description
Supersede 0 ("newIssuer") (address) Transfer issuing rights of Contract
Issue 1 ("amount") (amount) Issue new Tokens (only address with issuing rights can execute this function)
Destroy 2 ("amount") (amout) Destroy an amount of tokens (only address with issuing rights can execute this function)
Send 3 ("recipient", "amount") (address, amount) Send tokens
Transfer 4 ("sender", "recipient", "amount") (address, address, amount) Transfer tokens from sender to recipient
Deposit 5 ("sender", "contract", "amount") (address, contract_account, amount) Deposit tokens into another contract
Withdraw 6 ("contract", "recipient", "amount") (contract_account, address, amount) Withdraw tokens from another contract
TotalSupply 7 () () Currently not used
MaxSupply 8 () () Currently not used
BalanceOf 9 ("address") (address) Currently not used
GetIssuer 10 () () Currently not used

Supersede the issuing rights to another address

token_with_split_contract_id = "<your_token_with_split_contract_id>"

recipient_address = "<your_recipient_address>"

supersede_function_id = token_with_split_contract_helper.supersede_function_index

supersede_data_stack = token_with_split_contract_helper.supersede_data_stack_generator(recipient_address)

sender.execute_contract(token_with_split_contract_id, supersede_function_id, supersede_data_stack)

Issue tokens to owner of contract

issue_function_id = token_with_split_contract_helper.issue_function_index

issue_data_stack = token_with_split_contract_helper.issue_data_stack_generator(<your_issue_amount>)

sender.execute_contract(token_with_split_contract_id, issue_function_id, issue_data_stack)

Destroy a number of tokens from owner of contract

destroy_function_id = token_with_split_contract_helper.destroy_function_index

destroy_data_stack = token_with_split_contract_helper.destroy_data_stack_generator(<your_destroy_amount>)

sender.execute_contract(token_with_split_contract_id, destroy_function_id, destroy_data_stack)

Split the token and give it a new unity value

split_function_id = token_with_split_contract_helper.split_function_index

split_data_stack = token_with_split_contract_helper.destroy_data_stack_generator(<your_new_unity>)

sender.execute_contract(token_with_split_contract_id, split_function_id, split_data_stack)

Send tokens to other wallets

recipient_address = "<your_recipient_address>"

send_function_id = token_with_split_contract_helper.send_function_index

send_data_stack = token_with_split_contract_helper.send_data_stack_generator(recipient_address, <your_send_amount>)

sender.execute_contract(token_with_split_contract_id, send_function_id, send_data_stack)

Transfer tokens from one wallet to another

recipient_address = "<your_recipient_address>"

transfer_function_id = token_with_split_contract_helper.transfer_function_index

transfer_data_stack = token_with_split_contract_helper.transfer_data_stack_generator(sender.address, recipient_address, <your_transfer_amount>)

sender.execute_contract(token_with_split_contract_id, transfer_function_id, transfer_data_stack)

Deposit tokens into VSYS contracts (this example uses a payment channel contract)

payment_channel_contract_id = "<your_payment_channel_contract_id>"

deposit_function_id = token_with_split_contract_helper.deposit_function_index

deposit_data_stack = token_with_split_contract_helper.deposit_data_stack_generator(sender.address, payment_channel_contract_id, <your_deposit_amount>)

sender.execute_contract(token_with_split_contract_id, deposit_function_id, deposit_data_stack)

Withdraw tokens from VSYS contracts (this example uses a payment channel contract)

payment_channel_contract_id = "<your_payment_channel_contract_id>"

withdraw_function_id = token_with_split_contract_helper.withdraw_function_index

withdraw_data_stack = token_with_split_contract_helper.withdraw_data_stack_generator(payment_channel_contract_id, sender.address, <your_withdraw_amount>)

sender.execute_contract(token_with_split_contract_id, withdraw_function_id, withdraw_data_stack)

 

Querying the contract database

In order for the contract to do anything, it has to store some information within the database. This information can be queried by using the correct database key within the full node. The contract helper objects contain the corresponding database keys for each stored variable.

Both with split and without split token contracts have the same databases.

State Variable State Variable Index Description
issuer 0 The address of the issuer of the token contract
maker 1 The address of the creator of the token contract
State Map State Map Index State Map Key Description
N/A N/A N/A N/A

Get the issuer of the token contract

token_with_split_contract_id = "<your_token_with_split_contract_id>"

issuer_db_key = token_with_split_contract_helper.issuer_db_key_generator()

print(chain.contract_db_query(token_with_split_contract_id, issuer_db_key))

Get the maker of the token contract

token_with_split_contract_id = "<your_token_with_split_contract_id>"

maker_db_key = token_with_split_contract_helper.maker_db_key_generator()

print(chain.contract_db_query(token_with_split_contract_id, maker_db_key))