feat: add interactive token deployment

This commit is contained in:
William Luke 2022-02-10 11:22:21 +03:00
parent 1498edbb07
commit d3f65798f1
16 changed files with 720 additions and 141 deletions

6
.gitignore vendored
View File

@ -1,3 +1,9 @@
__pycache__ __pycache__
*.pyc *.pyc
*.egg-info *.egg-info
.venv
build
.vscode
.idea
contracts
*.egg

File diff suppressed because one or more lines are too long

0
cic/actions/__init__.py Normal file
View File

96
cic/actions/deploy.py Normal file
View File

@ -0,0 +1,96 @@
# standard imports
import logging
import importlib
import os
# external imports
from cic_types.ext.metadata import MetadataRequestsHandler
from cic_types.ext.metadata.signer import Signer as MetadataSigner
# local imports
from cic import (
Proof,
Processor,
)
from cic.output import (
HTTPWriter,
KeyedWriterFactory,
)
from cic.meta import (
Meta,
MetadataWriter,
)
from cic.attachment import Attachment
from cic.network import Network
from cic.token import Token
from typing import Optional
logg = logging.getLogger(__name__)
def init_writers_from_config(config):
w = {
'meta': None,
'attachment': None,
'proof': None,
'ext': None,
}
for v in w.keys():
k = 'CIC_CORE_{}_WRITER'.format(v.upper())
(d, c) = config.get(k).rsplit('.', maxsplit=1)
m = importlib.import_module(d)
o = getattr(m, c)
w[v] = o
return w
def deploy(config, target: str,contract_directory: str, metadata_endpoint: Optional[str], keystore_directory: str, key_file_path: str, gpg_passphrase: str):
modname = 'cic.ext.{}'.format(target)
cmd_mod = importlib.import_module(modname)
writers = init_writers_from_config(config)
output_directory = os.path.join(contract_directory, 'out')
output_writer_path_meta = output_directory
if metadata_endpoint != None:
MetadataRequestsHandler.base_url = metadata_endpoint
MetadataSigner.gpg_path = os.path.join('/tmp')
MetadataSigner.key_file_path = key_file_path
MetadataSigner.gpg_passphrase = gpg_passphrase
writers['proof'] = KeyedWriterFactory(MetadataWriter, HTTPWriter).new
writers['attachment'] = KeyedWriterFactory(None, HTTPWriter).new
writers['meta'] = MetadataWriter
output_writer_path_meta = metadata_endpoint
ct = Token(path=contract_directory)
cm = Meta(path=contract_directory, writer=writers['meta'](path=output_writer_path_meta))
ca = Attachment(path=contract_directory, writer=writers['attachment'](path=output_writer_path_meta))
cp = Proof(path=contract_directory, attachments=ca, writer=writers['proof'](path=output_writer_path_meta))
cn = Network(path=contract_directory)
ca.load()
ct.load()
cp.load()
cm.load()
cn.load()
chain_spec = None
try:
chain_spec = config.get('CHAIN_SPEC')
except KeyError:
chain_spec = cn.chain_spec
config.add(chain_spec, 'CHAIN_SPEC', exists_ok=True)
logg.debug(f'CHAIN_SPEC config set to {str(chain_spec)}')
(rpc, signer) = cmd_mod.parse_adapter(config, keystore_directory)
ref = cn.resource(target)
chain_spec = cn.chain_spec(target)
logg.debug('found reference {} chain spec {} for target {}'.format(ref['contents'], chain_spec, target))
c = getattr(cmd_mod, 'new')(chain_spec, ref['contents'], cp, signer_hint=signer, rpc=rpc, outputs_writer=writers['ext'](path=output_directory))
c.apply_token(ct)
p = Processor(proof=cp, attachment=ca, metadata=cm, extensions=[c])
p.process()

View File

@ -1,6 +1,6 @@
# standard imports # standard imports
import os
import logging import logging
import os
# local imports # local imports
from .base import * from .base import *

351
cic/cmd/easy.py Normal file
View File

@ -0,0 +1,351 @@
# standard import
import importlib
import json
import logging
import os
import subprocess
import requests
# external imports
from chainlib.chain import ChainSpec
# local imports
from cic import Proof
from cic.actions.deploy import deploy
from cic.attachment import Attachment
from cic.meta import Meta
from cic.network import Network
from cic.token import Token
log = logging.getLogger(__name__)
def process_args(argparser):
argparser.add_argument(
"--skip-gen", action="store_true", default=False, help="Skip Generation"
)
argparser.add_argument(
"--skip-deploy",
action="store_true",
help="Skip Deployment",
)
argparser.add_argument(
"--target",
default="eth",
help="Contract Tech Target (eth)",
)
argparser.add_argument(
"path",
type=str,
help="Path to generate/use contract deployment info",
)
argparser.add_argument(
"-p",
type=str,
help="RPC Provider (http://localhost:8545)",
)
def validate_args(args):
pass
CONTRACTS = [
{
"url": "https://gitlab.com/cicnet/eth-erc20/-/raw/master/python/giftable_erc20_token/data/GiftableToken",
"name": "Giftable Token",
},
{
"url": "https://gitlab.com/cicnet/erc20-demurrage-token/-/raw/master/python/erc20_demurrage_token/data/DemurrageTokenMultiCap",
"name": "Demurrage Token Multi Cap (Might not work)",
},
{
"url": "https://gitlab.com/cicnet/erc20-demurrage-token/-/raw/master/python/erc20_demurrage_token/data/DemurrageTokenMultiNocap",
"name": "Demurrage Token Multi No Cap (Might not work)",
},
{
"url": "https://gitlab.com/cicnet/erc20-demurrage-token/-/raw/master/python/erc20_demurrage_token/data/DemurrageTokenSingleCap",
"name": "Demurrage Token Single Cap (Might not work)",
},
{
"url": "https://gitlab.com/cicnet/erc20-demurrage-token/-/raw/master/python/erc20_demurrage_token/data/DemurrageTokenSingleNocap",
"name": "Demurrage Token Single No Cap",
},
]
# Download File from Url
def download_file(url: str, directory: str, filename=None) -> (str, bytes):
os.makedirs(directory, exist_ok=True)
filename = filename if filename else url.split("/")[-1]
path = os.path.join(directory, filename)
if not os.path.exists(path):
log.debug(f"Downloading {filename}")
r = requests.get(url, allow_redirects=True)
open(path, "wb").write(r.content)
return path
return path
def get_contract_args(data: list):
for item in data:
if item["type"] == "constructor":
return item["inputs"]
raise Exception("No constructor found in contract")
def print_contract_args(json_path: str):
json_data = json.load(open(json_path))
print(f"Contract Args:")
for contract_arg in get_contract_args(json_data):
print(
f"\t{contract_arg.get('name', '<no name>')} - {contract_arg.get('type', '<no type>')}"
)
def select_contract():
print(f"Contracts:")
print(f"\t C - Custom (path/url to contract)")
for idx, contract in enumerate(CONTRACTS):
print(f"\t {idx} - {contract['name']}")
val = input("Select contract (C,0,1..): ")
if val.isdigit() and int(val) < len(CONTRACTS):
contract = CONTRACTS[int(val)]
directory = f"./contracts/{contract['name']}"
bin_path = os.path.abspath(download_file(contract["url"] + ".bin", directory))
json_path = download_file(contract["url"] + ".json", directory)
elif val == "C":
possible_bin_location = input("Enter path/url to contract: ")
# possible_bin_location is path
if possible_bin_location[0] == "." or possible_bin_location[0] == "/":
if os.path.exists(possible_bin_location):
bin_path = os.path.abspath(possible_bin_location)
else:
raise Exception(f"File {possible_bin_location} does not exist")
possible_json_path = val.replace(".bin", ".json")
if os.path.exists(possible_json_path):
json_path = possible_json_path
# possible_bin_location is url
else:
bin_path = download_file(contract["url"] + ".bin", directory)
else:
print("Invalid selection")
exit(1)
extra_args = []
extra_args_types = []
if os.path.exists(json_path):
json_data = json.load(open(json_path))
for contract_arg in get_contract_args(json_data):
arg_name = contract_arg.get("name")
arg_type = contract_arg.get("type")
if arg_name not in ["_decimals", "_name", "_symbol"]:
val = input(f"Enter value for {arg_name} ({arg_type}): ")
extra_args.append(val)
extra_args_types.append(arg_type)
return {
"bin_path": bin_path,
"json_path": json_path,
"extra_args": extra_args,
"extra_args_types": extra_args_types,
}
def init_token(
directory: str,
code="",
extra_args=[],
extra_args_types=[],
):
contract = select_contract()
code = contract["bin_path"]
extra_args = contract["extra_args"]
extra_args_types = contract["extra_args_types"]
name = input("Enter Token Name (Foo Token): ") or "Foo Token"
symbol = input("Enter Token Symbol (FOO): ") or "FOO"
precision = input("Enter Token Precision (6): ") or 6
supply = input("Enter Token Supply (0): ") or 0
contract_token = Token(
directory,
name=name,
symbol=symbol,
precision=precision,
extra_args=extra_args,
extra_args_types=extra_args_types,
supply=supply,
code=code,
)
contract_token.start()
return contract_token
def init_proof(directory):
description = input("Enter Proof Description (None): ") or None
namespace = input("Enter Proof Namespace (ge): ") or "ge"
issuer = input("Enter Proof Issuer (None): ") or None
contract_proof = Proof(directory, description, namespace, issuer)
contract_proof.start()
return contract_proof
def init_meta(directory):
name = input("Enter Name (None): ") or ""
country_code = input("Enter Country Code (KE): ") or "KE"
location = input("Enter Location (None): ") or ""
adding_contact_info = True
contact = {}
while adding_contact_info:
value = input("Enter contact info (e.g 'phone: +254723522718'): ") or None
if value:
data = value.split(":")
if len(data) != 2:
print("Invalid contact info, you must enter in the format 'key: value'")
continue
contact[data[0].strip()] = data[1].strip()
else:
adding_contact_info = False
contract_meta = Meta(
directory,
name=name,
country_code=country_code,
location=location,
contact=contact,
)
contract_meta.start()
return contract_meta
def init_attachment(directory):
contract_attchment = Attachment(directory)
contract_attchment.start()
input(
f"Please add attachment files to '{os.path.abspath(os.path.join(directory,'attachments'))}' and then press ENTER to continue"
)
contract_attchment.load()
return contract_attchment
def init_network(
directory, registry_address,key_account_address, chain_spec, rpc_provider, targets=["eth"]
):
contract_network = Network(directory, targets=targets)
contract_network.start()
for target in targets:
m = importlib.import_module(f"cic.ext.{target}.start")
m.extension_start(
contract_network,
registry_address=registry_address,
chain_spec=chain_spec,
rpc_provider=rpc_provider,
key_account_address=key_account_address
)
contract_network.load()
return contract_network
def execute(config, eargs):
directory = eargs.path
if os.path.exists(directory):
contine = input(
"Directory already exists, Would you like to delete it? (y/n): "
)
if contine.lower() != "y":
print("Exiting")
exit(1)
else:
print(f"Deleted {directory}")
os.system(f"rm -rf {directory}")
target = eargs.target
if not eargs.skip_gen:
os.makedirs(directory)
# Defaults
default_contract_registry = config.get(
"CIC_CONTRACT_REGISTRY_ADDRESS",
"0xcf60ebc445b636a5ab787f9e8bc465a2a3ef8299",
)
default_key_account = config.get(
"CIC_KEY_ACCOUNT_ADDRESS", "eb3907ecad74a0013c259d5874ae7f22dcbcc95c"
)
default_metadata_endpoint = "http://localhost:63380" or config.get(
"META_ENDPOINT", "http://localhost:63380"
)
default_wallet_keyfile = config.get(
"WALLET_KEY_FILE",
"/home/will/grassroots/cic-internal-integration/apps/cic-ussd/tests/data/pgp/privatekeys_meta.asc",
)
default_wallet_passphrase = config.get("WALLET_PASSPHRASE", "merman")
default_chain_spec = config.get("CHAIN_SPEC", "evm:byzantium:8996:bloxberg")
default_rpc_provider = config.get("RPC_PROVIDER", "http://localhost:63545")
# Options
contract_registry = (
input(f"Enter Contract Registry ({default_contract_registry}): ")
or default_contract_registry
)
rpc_provider = (
input(f"Enter RPC Provider ({default_rpc_provider}): ")
or default_rpc_provider
)
chain_spec = ChainSpec.from_chain_str(
(input(f"Enter ChainSpec ({default_chain_spec}): ") or default_chain_spec)
)
key_account = (
input(f"Enter KeyAccount ({default_key_account}): ") or default_key_account
)
metadata_endpoint = (
input(f"Enter Metadata Endpoint ({default_metadata_endpoint}): ")
or default_metadata_endpoint
)
token = init_token(directory)
proof = init_proof(directory)
meta = init_meta(directory)
attachment = init_attachment(directory)
network = init_network(
directory,
registry_address=contract_registry,
key_account_address=key_account,
chain_spec=chain_spec,
rpc_provider=rpc_provider,
targets=[target],
)
print(f"[cic.header]\nversion = {proof.version()}\n")
print(f"[cic.token]\n{token}")
print(f"[cic.proof]\n{proof}")
print(f"[cic.meta]\n{meta}")
print(f"[cic.attachment]\n{attachment}")
print(f"[cic.network]\n{network}")
if not eargs.skip_deploy:
ready_to_deploy = input("Ready to deploy? (y/n): ")
if ready_to_deploy == "y":
deploy(
config,
contract_directory=directory,
gpg_passphrase=default_wallet_passphrase,
key_file_path=default_wallet_keyfile,
metadata_endpoint=metadata_endpoint,
keystore_directory="/home/will/grassroots/cic-internal-integration/apps/contract-migration/keystore",
target=target,
)
print("Deployed")
else:
print("Not deploying")
#
#
# rpc="http://localhost:63545"
# python -m cic.runnable.cic_cmd init --target eth --name "$token_name" --symbol $token_symbol --precision 6 $token_symbol_lowercase
# python -m cic.runnable.cic_cmd ext -p $rpc -i $chain_spec --registry $contract_registry -d $token_symbol_lowercase eth -vv
# python -m cic.runnable.cic_cmd export -p $rpc --metadata-endpoint http://localhost:63380 -vv -y /home/will/grassroots/cic-internal-integration/apps/contract-migration/keystore -o $token_symbol_lowercase/out -d $token_symbol_lowercase eth
if __name__ == "__main__":
execute()

View File

@ -23,7 +23,7 @@ from cic.meta import (
from cic.attachment import Attachment from cic.attachment import Attachment
from cic.network import Network from cic.network import Network
from cic.token import Token from cic.token import Token
from typing import Optional
logg = logging.getLogger(__name__) logg = logging.getLogger(__name__)
@ -56,8 +56,9 @@ def init_writers_from_config(config):
return w return w
EArgs = {'target': str, 'directory': str, 'output_directory': str, 'metadata_endpoint': Optional[str], 'y': str}
def execute(config, eargs): def execute(config, eargs: EArgs):
modname = 'cic.ext.{}'.format(eargs.target) modname = 'cic.ext.{}'.format(eargs.target)
cmd_mod = importlib.import_module(modname) cmd_mod = importlib.import_module(modname)
@ -67,7 +68,7 @@ def execute(config, eargs):
if eargs.metadata_endpoint != None: if eargs.metadata_endpoint != None:
MetadataRequestsHandler.base_url = eargs.metadata_endpoint MetadataRequestsHandler.base_url = eargs.metadata_endpoint
MetadataSigner.gpg_path = os.path.join('/tmp') MetadataSigner.gpg_path = os.path.join('/tmp')
MetadataSigner.key_file_path = '/home/lash/src/client/cic/grassrootseconomics/cic-internal-integration/apps/cic-ussd/tests/data/pgp/privatekeys_meta.asc' MetadataSigner.key_file_path = '/home/will/grassroots/cic-internal-integration/apps/cic-ussd/tests/data/pgp/privatekeys_meta.asc'
MetadataSigner.gpg_passphrase = 'merman' MetadataSigner.gpg_passphrase = 'merman'
writers['proof'] = KeyedWriterFactory(MetadataWriter, HTTPWriter).new writers['proof'] = KeyedWriterFactory(MetadataWriter, HTTPWriter).new
writers['attachment'] = KeyedWriterFactory(None, HTTPWriter).new writers['attachment'] = KeyedWriterFactory(None, HTTPWriter).new

View File

@ -25,6 +25,6 @@ def execute(config, eargs):
chain_spec = ChainSpec.from_chain_str(eargs.i) chain_spec = ChainSpec.from_chain_str(eargs.i)
m = importlib.import_module('cic.ext.{}.start'.format(eargs.target)) m = importlib.import_module(f'cic.ext.{eargs.target}.start')
m.extension_start(cn, registry_address=eargs.registry, chain_spec=chain_spec, rpc_provider=config.get('RPC_PROVIDER')) m.extension_start(cn, registry_address=eargs.registry, chain_spec=chain_spec, rpc_provider=config.get('RPC_PROVIDER'))

View File

@ -3,3 +3,10 @@ meta_writer = cic.output.KVWriter
attachment_writer = cic.output.KVWriter attachment_writer = cic.output.KVWriter
proof_writer = cic.output.KVWriter proof_writer = cic.output.KVWriter
ext_writer = cic.output.KVWriter ext_writer = cic.output.KVWriter
[cic]
contract_registry_address =
key_account_address =
[meta]
endpoint=https://meta.grassecon.net

View File

@ -1,6 +1,6 @@
# external imports # external imports
from cic_eth_registry import CICRegistry
from chainlib.eth.connection import RPCConnection from chainlib.eth.connection import RPCConnection
from cic_eth_registry import CICRegistry
def extension_start(network, *args, **kwargs): def extension_start(network, *args, **kwargs):
@ -9,18 +9,26 @@ def extension_start(network, *args, **kwargs):
:param network: Network object to read and write settings from :param network: Network object to read and write settings from
:type network: cic.network.Network :type network: cic.network.Network
""" """
CICRegistry.address = kwargs['registry_address'] CICRegistry.address = kwargs["registry_address"]
RPCConnection.register_location(kwargs['rpc_provider'], kwargs['chain_spec']) key_account_address = kwargs["key_account_address"] or ""
conn = RPCConnection.connect(kwargs['chain_spec'])
registry = CICRegistry(kwargs['chain_spec'], conn) RPCConnection.register_location(kwargs["rpc_provider"], kwargs["chain_spec"])
conn = RPCConnection.connect(kwargs["chain_spec"])
address_declarator = registry.by_name('AddressDeclarator') registry = CICRegistry(kwargs["chain_spec"], conn)
network.resource_set('eth', 'address_declarator', address_declarator)
token_index = registry.by_name('TokenRegistry') address_declarator = registry.by_name("AddressDeclarator")
network.resource_set('eth', 'token_index', token_index) network.resource_set(
"eth", "address_declarator", address_declarator, key_account=key_account_address
)
network.set('eth', kwargs['chain_spec']) token_index = registry.by_name("TokenRegistry")
network.resource_set(
"eth", "token_index", token_index, key_account=key_account_address
)
network.resource_set("eth", "token", None, key_account=key_account_address)
network.set("eth", kwargs["chain_spec"])
network.save() network.save()

View File

@ -1,21 +1,20 @@
# standard imports # standard imports
import os import base64
import json import json
import logging import logging
import base64 import os
# external imports # external imports
from cic_types import MetadataPointer from cic_types import MetadataPointer
from cic_types.processor import generate_metadata_pointer
from cic_types.ext.metadata import MetadataRequestsHandler from cic_types.ext.metadata import MetadataRequestsHandler
from cic_types.processor import generate_metadata_pointer
from hexathon import strip_0x from hexathon import strip_0x
# local imports
from .base import (
Data,
data_dir,
)
from cic.output import OutputWriter from cic.output import OutputWriter
# local imports
from .base import Data, data_dir
logg = logging.getLogger(__name__) logg = logging.getLogger(__name__)
@ -29,10 +28,12 @@ class Meta(Data):
:param writer: Writer interface receiving the output of the processor :param writer: Writer interface receiving the output of the processor
:type writer: cic.output.OutputWriter :type writer: cic.output.OutputWriter
""" """
def __init__(self, path='.', writer=None): def __init__(self, path='.', writer=None, name="", location="", country_code="", contact={}):
super(Meta, self).__init__() super(Meta, self).__init__()
self.name = None self.name = None
self.contact = {} self.contact = contact
self.country_code = country_code
self.location = location
self.path = path self.path = path
self.writer = writer self.writer = writer
self.meta_path = os.path.join(self.path, 'meta.json') self.meta_path = os.path.join(self.path, 'meta.json')
@ -49,7 +50,8 @@ class Meta(Data):
self.name = o['name'] self.name = o['name']
self.contact = o['contact'] self.contact = o['contact']
self.country_code = o['country_code']
self.location = o['location']
self.inited = True self.inited = True
@ -64,6 +66,11 @@ class Meta(Data):
o = json.load(f) o = json.load(f)
f.close() f.close()
o['name'] = self.name
o['contact'] = self.contact
o['country_code'] = self.country_code
o['location'] = self.location
f = open(self.meta_path, 'w') f = open(self.meta_path, 'w')
json.dump(o, f, sort_keys=True, indent="\t") json.dump(o, f, sort_keys=True, indent="\t")
f.close() f.close()
@ -107,12 +114,15 @@ class Meta(Data):
def __str__(self): def __str__(self):
s = "contact.name = {}\n".format(self.name) s = f"contact.name = {self.name}\n"
s = f"contact.country_code = {self.country_code}\n"
for k in self.contact.keys(): s = f"contact.location = {self.location}\n"
if self.contact[k] == '': for contact_key in self.contact.keys():
contact_value = self.contact[contact_key]
if not contact_value:
s += f"contact.{contact_key} = \n"
continue continue
s += "contact.{} = {}\n".format(k.lower(), self.contact[k]) s += f"contact.{contact_key} = {contact_value}\n"
return s return s

View File

@ -54,7 +54,7 @@ class Network(Data):
""" """
super(Network, self).load() super(Network, self).load()
network_template_file_path = os.path.join(data_dir, 'network_template_v{}.json'.format(self.version())) network_template_file_path = os.path.join(data_dir, f'network_template_v{self.version()}.json')
f = open(network_template_file_path) f = open(network_template_file_path)
o_part = json.load(f) o_part = json.load(f)
@ -138,11 +138,11 @@ class Network(Data):
def __str__(self): def __str__(self):
s = '' s = ''
for k in self.resources.keys(): for resource in self.resources.keys():
for kk in self.resources[k]['contents'].keys(): for content_key in self.resources[resource]['contents'].keys():
v = self.resources[k]['contents'][kk] content_value = self.resources[resource]['contents'][content_key]
if v == None: if content_value == None:
v = '' content_value = ''
s += '{}.{} = {}\n'.format(k, kk, v) s += f'{resource}.{content_key} = {content_value}\n'
return s return s

View File

@ -33,34 +33,40 @@ class Proof(Data):
:type writer: cic.output.OutputWriter :type writer: cic.output.OutputWriter
""" """
def __init__(self, path='.', attachments=None, writer=None): def __init__(
self,
path=".",
description=None,
namespace="ge",
issuer=None,
attachments=None,
writer=None,
):
super(Proof, self).__init__() super(Proof, self).__init__()
self.proofs = [] self.proofs = []
self.namespace = 'ge' self.namespace = namespace
self.description = None self.description = description
self.issuer = None self.issuer = issuer
self.path = path self.path = path
self.writer = writer self.writer = writer
self.extra_attachments = attachments self.extra_attachments = attachments
self.attachments = {} self.attachments = {}
self.proof_path = os.path.join(self.path, 'proof.json') self.proof_path = os.path.join(self.path, "proof.json")
self.temp_proof_path = tempfile.mkstemp()[1] self.temp_proof_path = tempfile.mkstemp()[1]
def load(self): def load(self):
"""Load proof data from settings. """Load proof data from settings."""
"""
super(Proof, self).load() super(Proof, self).load()
f = open(self.proof_path, 'r') f = open(self.proof_path, "r")
o = json.load(f) o = json.load(f)
f.close() f.close()
self.set_version(o['version']) self.set_version(o["version"])
self.description = o['description'] self.description = o["description"]
self.namespace = o['namespace'] self.namespace = o["namespace"]
self.issuer = o['issuer'] self.issuer = o["issuer"]
self.proofs = o['proofs'] self.proofs = o["proofs"]
if self.extra_attachments != None: if self.extra_attachments != None:
a = self.extra_attachments.asdict() a = self.extra_attachments.asdict()
@ -72,35 +78,34 @@ class Proof(Data):
self.inited = True self.inited = True
def start(self): def start(self):
"""Initialize proof settings from template. """Initialize proof settings from template."""
"""
super(Proof, self).start() super(Proof, self).start()
proof_template_file_path = os.path.join(data_dir, 'proof_template_v{}.json'.format(self.version())) proof_template_file_path = os.path.join(
data_dir, "proof_template_v{}.json".format(self.version())
)
f = open(proof_template_file_path) f = open(proof_template_file_path)
o = json.load(f) o = json.load(f)
f.close() f.close()
o["issuer"] = self.issuer
f = open(self.proof_path, 'w') o["description"] = self.description
o["namespace"] = self.namespace
f = open(self.proof_path, "w")
json.dump(o, f, sort_keys=True, indent="\t") json.dump(o, f, sort_keys=True, indent="\t")
f.close() f.close()
def asdict(self): def asdict(self):
"""Output proof state to dict. """Output proof state to dict."""
"""
return { return {
'version': self.version(), "version": self.version(),
'namespace': self.namespace, "namespace": self.namespace,
'description': self.description, "description": self.description,
'issuer': self.issuer, "issuer": self.issuer,
'proofs': self.proofs, "proofs": self.proofs,
} }
# TODO: the efficiency of this method could probably be improved. # TODO: the efficiency of this method could probably be improved.
def __get_ordered_hashes(self): def __get_ordered_hashes(self):
ks = list(self.attachments.keys()) ks = list(self.attachments.keys())
@ -108,30 +113,26 @@ class Proof(Data):
return ks return ks
# def get(self): # def get(self):
# hsh = self.hash(b).hex() # hsh = self.hash(b).hex()
# self.attachments[hsh] = self.temp_proof_path # self.attachments[hsh] = self.temp_proof_path
# logg.debug('cbor of {} is {} hashes to {}'.format(v, b.hex(), hsh)) # logg.debug('cbor of {} is {} hashes to {}'.format(v, b.hex(), hsh))
def root(self): def root(self):
"""Calculate the root digest from the serialized proof object. """Calculate the root digest from the serialized proof object."""
"""
v = self.asdict() v = self.asdict()
# b = cbor2.dumps(v) # b = cbor2.dumps(v)
b = json.dumps(v) b = json.dumps(v)
f = open(self.temp_proof_path, 'w') f = open(self.temp_proof_path, "w")
f.write(b) f.write(b)
f.close() f.close()
b = b.encode('utf-8') b = b.encode("utf-8")
k = self.hash(b) k = self.hash(b)
return (k.hex(), b) return (k.hex(), b)
def process(self, token_address=None, token_symbol=None, writer=None): def process(self, token_address=None, token_symbol=None, writer=None):
"""Serialize and publish proof. """Serialize and publish proof.
@ -144,8 +145,10 @@ class Proof(Data):
writer.write(k, v) writer.write(k, v)
root_key = k root_key = k
token_symbol_bytes = token_symbol.encode('utf-8') token_symbol_bytes = token_symbol.encode("utf-8")
k = generate_metadata_pointer(token_symbol_bytes, MetadataPointer.TOKEN_PROOF_SYMBOL) k = generate_metadata_pointer(
token_symbol_bytes, MetadataPointer.TOKEN_PROOF_SYMBOL
)
writer.write(k, v) writer.write(k, v)
token_address_bytes = bytes.fromhex(strip_0x(token_address)) token_address_bytes = bytes.fromhex(strip_0x(token_address))
@ -170,12 +173,11 @@ class Proof(Data):
# writer.write(r_hex, hshs_cat) # writer.write(r_hex, hshs_cat)
o = self.asdict() o = self.asdict()
f = open(self.proof_path, 'w') f = open(self.proof_path, "w")
json.dump(o, f, sort_keys=True, indent="\t") json.dump(o, f, sort_keys=True, indent="\t")
f.close() f.close()
return root_key return root_key
def __str__(self): def __str__(self):
return "description = {}\n".format(self.description) return "description = {}\n".format(self.description)

View File

@ -11,6 +11,7 @@ import cic.cmd.init as cmd_init
import cic.cmd.show as cmd_show import cic.cmd.show as cmd_show
import cic.cmd.ext as cmd_ext import cic.cmd.ext as cmd_ext
import cic.cmd.export as cmd_export import cic.cmd.export as cmd_export
import cic.cmd.easy as cmd_easy
logging.basicConfig(level=logging.WARNING) logging.basicConfig(level=logging.WARNING)
logg = logging.getLogger() logg = logging.getLogger()
@ -34,6 +35,8 @@ cmd_export.process_args(sub_export)
sub_ext = sub.add_parser('ext', help='extension helpers') sub_ext = sub.add_parser('ext', help='extension helpers')
cmd_ext.process_args(sub_ext) cmd_ext.process_args(sub_ext)
sub_easy = sub.add_parser('easy', help='Easy Mode Contract Deployment')
cmd_easy.process_args(sub_easy)
args = argparser.parse_args(sys.argv[1:]) args = argparser.parse_args(sys.argv[1:])

View File

@ -1,12 +1,9 @@
# standard imports # standard imports
import os
import json import json
import os
# local imports # local imports
from .base import ( from .base import Data, data_dir
Data,
data_dir,
)
class Token(Data): class Token(Data):
@ -27,40 +24,49 @@ class Token(Data):
:param code: Bytecode for token chain application :param code: Bytecode for token chain application
:type code: str (hex) :type code: str (hex)
""" """
def __init__(self, path='.', name=None, symbol=None, precision=1, supply=0, code=None):
def __init__(
self,
path=".",
name=None,
symbol=None,
precision=1,
supply=0,
code=None,
extra_args=[],
extra_args_types=[],
):
super(Token, self).__init__() super(Token, self).__init__()
self.name = name self.name = name
self.symbol = symbol self.symbol = symbol
self.supply = supply self.supply = supply
self.precision = precision self.precision = precision
self.code = code self.code = code
self.extra_args: list = [] self.extra_args = extra_args
self.extra_args_types: list = [] self.extra_args_types = extra_args_types
self.path = path self.path = path
self.token_path = os.path.join(self.path, 'token.json') self.token_path = os.path.join(self.path, "token.json")
def load(self): def load(self):
"""Load token data from settings. """Load token data from settings."""
"""
super(Token, self).load() super(Token, self).load()
f = open(self.token_path, 'r') f = open(self.token_path, "r")
o = json.load(f) o = json.load(f)
f.close() f.close()
self.name = o['name'] self.name = o["name"]
self.symbol = o['symbol'] self.symbol = o["symbol"]
self.precision = o['precision'] self.precision = o["precision"]
self.code = o['code'] self.code = o["code"]
self.supply = o['supply'] self.supply = o["supply"]
extras = [] extras = []
extra_types = [] extra_types = []
token_extras: list = o['extra'] token_extras: list = o["extra"]
if token_extras: if token_extras:
for token_extra in token_extras: for token_extra in token_extras:
arg = token_extra.get('arg') arg = token_extra.get("arg")
arg_type = token_extra.get('arg_type') arg_type = token_extra.get("arg_type")
if arg: if arg:
extras.append(arg) extras.append(arg)
if arg_type: if arg_type:
@ -69,32 +75,40 @@ class Token(Data):
self.extra_args_types = extra_types self.extra_args_types = extra_types
self.inited = True self.inited = True
def start(self): def start(self):
"""Initialize token settings from arguments passed to the constructor and/or template. """Initialize token settings from arguments passed to the constructor and/or template."""
"""
super(Token, self).load() super(Token, self).load()
token_template_file_path = os.path.join(data_dir, 'token_template_v{}.json'.format(self.version())) token_template_file_path = os.path.join(
data_dir, "token_template_v{}.json".format(self.version())
)
f = open(token_template_file_path) f = open(token_template_file_path)
o = json.load(f) o = json.load(f)
f.close() f.close()
o["name"] = self.name
o["symbol"] = self.symbol
o["precision"] = self.precision
o["code"] = self.code
o["supply"] = self.supply
extra = []
for i in range(len(self.extra_args)):
extra.append(
{"arg": self.extra_args[i], "arg_type": self.extra_args_types[i]}
)
if len(extra):
o["extra"] = extra
print(extra)
o['name'] = self.name f = open(self.token_path, "w")
o['symbol'] = self.symbol
o['precision'] = self.precision
o['code'] = self.code
o['supply'] = self.supply
f = open(self.token_path, 'w')
json.dump(o, f, sort_keys=True, indent="\t") json.dump(o, f, sort_keys=True, indent="\t")
f.close() f.close()
def __str__(self): def __str__(self):
s = """name = {} s = """name = {}
symbol = {} symbol = {}
precision = {} precision = {}
""".format(self.name, self.symbol, self.precision) """.format(
self.name, self.symbol, self.precision
)
return s return s

View File

@ -3,3 +3,4 @@ cic-types~=0.2.1a5
confini~=0.5.1 confini~=0.5.1
chainlib~=0.0.13 chainlib~=0.0.13
cbor2==5.4.1 cbor2==5.4.1
click==8.0.3