Table of Contents
Welcome to WEB3 CLI¶
This is a Command Line program to interact with your NFTs, Cryptocurrencies etc. via the ThirdWeb Platform. This is just a fun little project that I made to be able to connect to blockchains and Web3 from the command line.
Modules¶
These are the modules that are currently supported, I will add more as I can.
-
Currency- This module can be used to do all sorts of things like Minting new tokens, burning tokens, viewing the supply, transferring tokens etc.
-
NFT Collection- This module can be used to mint NFTs, transfer NFTs, view NFT data etc.
Project layout¶
This is the project file structure for reference.
docs/
index.md
docs_assets/
images/
favicon.ico
javascripts/
config.js
stylesheets/
pdf-export.css
theme/
main.html
modules/
currency_token/
balance.py
burn.py
get.py
mint.py
supply.py
transfer.py
value.py
nft_collection/
burn.py
mint.py
transfer.py
view_by_owner.py
view.py
collection.py
currency.py
.gitignore
docs-requirements.txt
main.py
mkdocs.yml
requirements.txt
Dependencies¶
This program depends on the following dependencies. Huge shoutout to all the maintainers and contributors of these packages.
Getting Started¶
First clone the repository¶
You will need to clone the repository locally.
git clone https://github.com/Arpan-206/Web3-CLI.git
Then install the required dependencies¶
Then you will need to install the required dependencies.
pip3 install -r requirements.txt
Run the program¶
Now, you can run the program by just running the main file.
python3 main.py
Installation¶
It is very easy to install dependencies and stuff for this module and run this program.
Cloning the repo¶
git clone https://github.com/Arpan-206/Web3-CLI.git
Installing the required dependencies¶
pip3 install -r requirements.txt
Installing the required dependencies for documentation¶
pip3 install -r docs-requirement.txt
The following are the dependencies for this project¶
This program depends on the following dependencies. Huge shoutout to all the maintainers and contributors of these packages.
Screenshots¶
Here are some of screenshots of the application. There are too many to show here but these should give you a good enough idea.
Modules
The Collection Module¶
These are the functions used to view or manipulate the NFT Collection module.
nft_collection(nft_module)
¶
This is the main function of the NFT collection module. It will prompt you to select the action that you want to do on the NFT collection module. Then it will call the corresponding function and that function takes on.
Source code in modules/collection.py
def nft_collection(nft_module):
"""
This is the main function of the NFT collection module. It will prompt you to select the action that you want to do on the NFT collection module. Then it will call the corresponding function and that function takes on.
"""
# This is the list of the actions that you can do on the NFT collection module.
actions = prompt([
{
'type': 'list',
'name': 'action',
'message': 'What do you want to do?',
'choices': [
Separator('-- Actions --'),
{
'name': 'Mint an NFT',
'value': 'mint',
'short': 'Mint'
},
{
'name': 'Transfer an NFT',
'value': 'transfer',
'short': 'Transfer'
},
{
'name': 'View an NFT',
'value': 'view',
'short': 'View'
},
{
'name': 'View all NFTs of a specific owner',
'value': 'view_by_owner',
'short': 'View By Owner'
},
{
'name': 'Burn an NFT',
'value': 'burn',
'short': 'Burn'
}
]
}
])
# Calling the corresponding function based on the action that you selected.
if actions['action'] == 'mint':
from .nft_collection.mint import mint_prompt
mint_prompt(nft_module=nft_module)
elif actions['action'] == 'transfer':
from .nft_collection.transfer import transfer_prompt
transfer_prompt(nft_module=nft_module)
elif actions['action'] == 'view':
from .nft_collection.view import view
view(nft_module=nft_module)
elif actions['action'] == 'burn':
from .nft_collection.burn import burn
burn(nft_module=nft_module)
elif actions['action'] == 'view_by_owner':
from .nft_collection.view_by_owner import view_by_owner
view_by_owner(nft_module=nft_module)
else:
print(colored('No Action Selected', 'red'))
sys.exit(1)
burn(nft_module)
¶
The function is used to burn an NFT.
Source code in nft_collection/burn.py
def burn(nft_module) -> None:
"""
The function is used to burn an NFT.
"""
# Getting the NFT to burn
burn_data = prompt([
{
'type': 'input',
'name': 'id',
'message': 'Enter the NFT ID',
'default': "0",
},
{
'type': 'confirm',
'name': 'confirmation',
'message': 'Do you want to burn the selected NFT?',
'default': False,
},
])
# Fetching the NFT id
id = int(burn_data['id'])
# Confirming the burn
if burn_data['confirmation']:
try:
# Burning the NFT
nft_module.burn(id)
print(colored('NFT burned successfully!', 'green'))
except Exception as e:
# Printing the error
print(colored('NFT could not be burned. \n' + e, 'red'))
else:
# Reporting if cancelled
print(colored('NFT not burned!', 'blue'))
mint(nft_module, name, description, image_uri, image_format='JPEG', properties={})
¶
This function is used to mint an NFT.
Source code in nft_collection/mint.py
def mint(nft_module, name: str, description: str, image_uri: str, image_format='JPEG', properties={}) -> str:
"""
This function is used to mint an NFT.
"""
# Checking if the image_uri is a local file or a remote file.
if image_format != 'URL':
try:
if image_uri == '':
byte_im = b''
else:
try:
# If the image_uri is a local file, then we will read the file and convert it to a byte array.
im = Image.open(image_uri)
byte_im = io.BytesIO()
im.save(byte_im, format=image_format)
byte_im = byte_im.getvalue()
nft_module.mint(MintArg(name=name,
description=description,
image_uri=byte_im,
properties=properties))
im_resize = im.resize((500, 500))
buf = io.BytesIO()
im_resize.save(buf, format=image_format)
byte_im = buf.getvalue()
except FileNotFoundError:
# File not found error.
print('File not found')
return
# Minting the NFT
nft_module.mint(MintArg(name=name,
description=description,
image_uri=byte_im,
properties=properties))
except requests.exceptions.ReadTimeout:
return 'A time out has occured. But, in most cases this is not a problem and the NFT is minted anyway. So, try to cross check before trying again.\n'
else:
# If the image_uri is a URL, then we will pass it straight on.
nft_module.mint(MintArg(name=name,
description=description,
image_uri=image_uri,
properties=properties))
return 'NFT minted successfully!\n'
transfer_prompt(nft_module)
¶
This function is used to transfer an NFT.
Source code in nft_collection/transfer.py
def transfer_prompt(nft_module) -> None:
"""
This function is used to transfer an NFT.
"""
# Getting the NFT to transfer
transfer_args = prompt([
{
'type': 'input',
'name': 'to',
'message': 'Who should receive the NFT?',
},
{
'type': 'input',
'name': 'id',
'message': 'NFT Token ID',
'default': '0'
},
])
try:
# Trying to execute the transfer
nft_module.transfer(to_address=transfer_args['to'],
token_id=transfer_args['id'],)
except ContractLogicError:
# Printing the error if the transfer failed
print(colored(
'Error: Either you do not own the NFT or some other error has occurred.', 'red'))
return
# Printing the success message
print(colored('NFT transferred successfully!\n', 'green'))
view_by_owner(nft_module)
¶
This function is used to view all NFTs of a specific owner.
Source code in nft_collection/view_by_owner.py
def view_by_owner(nft_module) -> None:
"""
This function is used to view all NFTs of a specific owner.
"""
# Getting the owner address
view_data = prompt([
{
'type': 'input',
'name': 'owner',
'message': 'Enter the Owners\'s Address',
}, {
'type': 'list',
'name': 'Print or Write to file?',
'message': 'Do you want to print the NFT metadata or write it to a file?',
'choices': [
Separator('-- Print or Write to file --'),
{
'name': 'Print',
'value': 'print',
'short': 'Print'
},
{
'name': 'Write to file',
'value': 'write',
'short': 'Write'
}
]
},
{
'type': 'input',
'name': 'file_name',
'message': 'Enter the file name (should be .json)',
'default': "nft_metadata.json",
'when': lambda answers: answers['Print or Write to file?'] == 'write',
'validate': lambda answer: 'Please enter a valid file name' if not answer.endswith('.json') else True
}
])
# Fetching the owner address
owner = view_data['owner']
data = nft_module.get_owned(owner)
# Printing the NFT metadata
if view_data['Print or Write to file?'] == 'print':
print(colored('NFTs owned by ' + owner + ':', 'green'))
for i in range(len(data)):
print(colored(
f'{data[i].id}: Name: {data[i].name}, Description: { data[i].description }, Image: { data[i].image }, URL: { data[i].uri }', 'blue'))
# Writing the NFT metadata to a file
elif view_data['Print or Write to file?'] == 'write':
data_dict = {}
for i in range(len(data)):
data_dict[str(i)] = {"ID": str(data[i].id), "Name": data[i].name, "Description": data[i].description, "Image": str(
data[i].image), "uri": data[i].uri, "Properties": data[i].properties}
with open(view_data['file_name'], 'w') as f:
f.write(json.dumps(data_dict, indent=4))
view(nft_module)
¶
This function is used to view an NFT.
Source code in nft_collection/view.py
def view(nft_module) -> None:
"""
This function is used to view an NFT.
"""
# Getting the NFT to view
view_data = prompt([
{
'type': 'input',
'name': 'id',
'message': 'Enter the NFT ID',
'default': "0",
},
{
'type': 'list',
'name': 'Print or Write to file?',
'message': 'Do you want to print the NFT metadata or write it to a file?',
'choices': [
Separator('-- Print or Write to file --'),
{
'name': 'Print',
'value': 'print',
'short': 'Print'
},
{
'name': 'Write to file',
'value': 'write',
'short': 'Write'
}
]
},
{
'type': 'input',
'name': 'file_name',
'message': 'Enter the file name (should be .json)',
'default': "nft_metadata.json",
'when': lambda answers: answers['Print or Write to file?'] == 'write',
'validate': lambda answer: 'Please enter a valid file name' if not answer.endswith('.json') else True
}
])
# Retreiving the NFT data
id = int(view_data['id'])
data = nft_module.get(id)
data_dict = {"ID": str(id), "Name": data.name, "Description": data.description, "Image": str(
data.image), "uri": data.uri, "Properties": data.properties}
# Printing the NFT metadata
if view_data['Print or Write to file?'] == 'print':
print(colored('NFT Data:', 'green'))
for key, value in data_dict.items():
print(colored(f'{key}: {value}', 'blue'))
# Writing the NFT metadata to a file
else:
with open(view_data['file_name'], 'w') as f:
f.write(json.dumps(data_dict))
print(colored('NFT Metadata written to file successfully!', 'green'))
The Currency Module¶
These are the various functions that are used to view or manipulate the currency module.
currency(currency_module)
¶
This module prompts you to select the action that you want to do on the currency module. Then it will call the corresponding function and that function takes on.
Source code in modules/currency.py
def currency(currency_module):
"""
This module prompts you to select the action that you want to do on the currency module. Then it will call the corresponding function and that function takes on.
"""
# This is the list of the actions that you can do on the currency module.
actions = prompt([
{
'type': 'list',
'name': 'action',
'message': 'What do you want to do?',
'choices': [
Separator('-- Actions --'),
{
'name': 'See the balance of your account',
'value': 'balance',
'short': 'Balance'
},
{
'name': 'Transfer some tokens to another account',
'value': 'transfer',
'short': 'Transfer'
},
{
'name': 'Burn some tokens',
'value': 'burn',
'short': 'Burn'
},
{
'name': 'See the balance of another account',
'value': 'balance_other',
'short': 'Balance Other'
},
{
'name': 'Get the value of a given amount of tokens',
'value': 'value',
'short': 'Value'
},
{
'name': 'Get the total supply of tokens',
'value': 'total_supply',
'short': 'Total Supply'
},
{
'name': 'Mint some tokens',
'value': 'mint',
'short': 'Mint'
}
]
},
{
'type': 'input',
'name': 'address',
'message': 'Enter the address of the other account',
'when': lambda answers: answers['action'] == 'balance_other'
}
])
# Calling the desired function.
if actions['action'] == 'balance':
from .currency_token.balance import balance
balance(currency_module)
elif actions['action'] == 'balance_other':
from .currency_token.balance import balance_of
balance_of(currency_module, actions['address'])
elif actions['action'] == 'mint':
from .currency_token.mint import mint
mint(currency_module)
elif actions['action'] == 'transfer':
from .currency_token.transfer import transfer
transfer(currency_module)
elif actions['action'] == 'value':
from .currency_token.value import value
value(currency_module)
elif actions['action'] == 'burn':
from .currency_token.burn import burn
burn(currency_module)
elif actions['action'] == 'total_supply':
from .currency_token.supply import supply
supply(currency_module)
else:
raise Exception('Invalid action')
balance(currency_module)
¶
This function is used to get your own current balance, i.e, get the number of tokens that you hold.
Source code in currency_token/balance.py
def balance(currency_module) -> None:
"""
This function is used to get your own current balance, i.e, get the number of tokens that you hold.
"""
details = get(currency_module)
print(colored(
f"The balance of current user is {currency_module.format_units(currency_module.balance(), details['decimals']) + ' ' + details['symbol']}.", 'green'))
balance_of(currency_module, address)
¶
This module is used to get your someone's current balance, i.e, get the number of tokens that you hold.
Source code in currency_token/balance.py
def balance_of(currency_module, address) -> None:
"""
This module is used to get your someone's current balance, i.e, get the number of tokens that you hold.
"""
details = get(currency_module)
print(colored(
f"The balance of {address} is {currency_module.format_units(currency_module.balance_of(address), details['decimals']) + ' ' + details['symbol']}.", 'green'))
burn(currency_module)
¶
This function is used to burn some tokens from your account.
Source code in currency_token/burn.py
def burn(currency_module):
"""
This function is used to burn some tokens from your account.
"""
# Get the amount of tokens to burn
burn_data = prompt([
{
'type': 'input',
'name': 'amount',
'message': 'Enter the amount of tokens to burn',
'default': "1",
},
{
'type': 'confirm',
'name': 'confirmation',
'message': 'Do you want to burn the selected tokens?',
'default': False,
},
])
# Convert the amount to the correct decimal format
amount = Decimal(burn_data['amount']) * \
(10 ** get(currency_module)['decimals'])
# Confirm the burn
if burn_data['confirmation']:
try:
try:
currency_module.burn(int(amount))
except TimeExhausted:
print(colored(
'A time exhaust has been detected. The tokens were most likely burnt. Please verify before trying again.', 'red'))
print(colored('Tokens burned successfully!', 'green'))
except Exception as e:
print(colored('Tokens could not be burned. \n' + e, 'red'))
else:
print(colored('Tokens not burned!', 'blue'))
get(currency_module)
¶
This helper function is used to get the details of the currency.
Source code in currency_token/get.py
def get(currency_module) -> Dict:
"""
This helper function is used to get the details of the currency.
"""
details = currency_module.get()
return {"name": details.name, "symbol": details.symbol, "decimals": details.decimals}
supply(currency_module)
¶
This function is used to get the total supply of the currency.
Source code in currency_token/supply.py
def supply(currency_module):
"""
This function is used to get the total supply of the currency.
"""
try:
total_supply = Decimal(currency_module.total_supply(
) / (10 ** get(currency_module)['decimals']))
print(colored(
f"Total supply of {get(currency_module)['symbol']} is {total_supply}", 'green'))
except Exception as e:
print(colored('Can\'t get total supply \n' + e, 'red'))
transfer(currency_module)
¶
This function is used to transfer some tokens from your account to another account.
Source code in currency_token/transfer.py
def transfer(currency_module):
"""
This function is used to transfer some tokens from your account to another account.
"""
transfer_data = prompt([
{
'type': 'input',
'name': 'amount',
'message': 'Enter the amount of tokens to transfer',
'default': "1",
},
{
'type': 'input',
'name': 'address',
'message': 'Enter the address of the other account',
},
{
'type': 'confirm',
'name': 'confirmation',
'message': 'Do you want to transfer the selected tokens?',
'default': False,
},
])
amount = Decimal(transfer_data['amount']) * \
(10 ** get(currency_module)['decimals'])
if transfer_data['confirmation']:
try:
signer_addr = currency_module.get_signer_address()
currency_module.set_allowance(signer_addr, amount)
currency_module.transfer_from(signer_addr,
transfer_data['address'], int(amount))
print(colored('Tokens transferred successfully!', 'green'))
except Exception as e:
print(colored('Tokens could not be transferred. \n' + e, 'red'))
value(currency_module)
¶
This function is used to get the value of the currency.
Source code in currency_token/value.py
def value(currency_module):
"""
This function is used to get the value of the currency.
"""
value_data = prompt([
{
'type': 'input',
'name': 'amount',
'message': 'Enter the amount of tokens to get the value of',
'default': "1",
},
])
amount = Decimal(value_data['amount']) * \
(10 ** get(currency_module)['decimals'])
try:
print(colored(
f"Value of {value_data['amount']} {get(currency_module)['symbol']}s is {currency_module.get_value(int(amount)).value} and its display value is {currency_module.get_value(int(amount)).display_value}", 'green'))
except Exception as e:
print(colored('Can\'t get value \n' + e, 'red'))