def aslp2Clone(tkid, no=None): """ Build a aslp2 clone transaction. Args: tkid (str): token id. no (str): token notes. Returns: dposlib.ark.tx.Transaction: orphan transaction with appropriate aslp2 `vendorField`. """ args = dict(tokenid=tkid) if no: args["notes"] = no[:32] smartbridge = GET.api.vendor_aslp2_clone(**args) if smartbridge.pop("status", 0) != 200: raise Exception(smartbridge.get("error", "aslp smartbridge error")) return Transaction(typeGroup=1, type=0, amount=1, recipientId=cfg.master_address, vendorField=json.dumps(smartbridge, separators=(",", ":")))
def aslp2Genesis(sy, na, du=None, no=None, pa=False): """ Build a aslp2 genesis transaction. Args: sy (str): token symbol. na (str): token name. du (str): URI. no (str): token notes. pa (bool): pausable token ? Returns: dposlib.ark.tx.Transaction: orphan transaction with appropriate aslp2 `vendorField`. """ args = dict(symbol=sy, name=na) if du: args["uri"] = du if no: args["notes"] = no[:32] if pa: args["pausable"] = "true" smartbridge = GET.api.vendor_aslp2_genesis(**args) if smartbridge.pop("status", 0) != 200: raise Exception(smartbridge.get("error", "aslp smartbridge error")) return Transaction(typeGroup=1, type=0, amount=100000000, recipientId=cfg.master_address, vendorField=json.dumps(smartbridge, separators=(",", ":")))
def transfer(amount, address, vendorField=None, expiration=0): """ Build a transfer transaction. Emoji can be included in transaction vendorField using unicode formating. ```python >>> vendorField = u"message with sparkles \u2728" ``` Args: amount (float): transaction amount in ark. address (str): valid recipient address. vendorField (str): vendor field message. expiration (float): time of persistance in hour. Returns: dposlib.ark.tx.Transaction: orphan transaction. """ if cfg.txversion > 1 and expiration > 0: block_remaining = expiration*60*60//rest.cfg.blocktime expiration = int( rest.GET.api.blockchain() .get("data", {}).get("block", {}).get("height", -block_remaining) + block_remaining ) return Transaction( type=0, amount=amount*100000000, recipientId=address, vendorField=vendorField, version=cfg.txversion, expiration=None if cfg.txversion < 2 else expiration )
def downVote(*usernames): """ Build a downvote transaction. Args: usernames (iterable): delegate usernames as str iterable. Returns: dposlib.ark.tx.Transaction: orphan transaction. """ try: votes = [ "-"+rest.GET.api.delegates(username, returnKey="data")["publicKey"] for username in usernames ] except KeyError: raise Exception( "one of delegate %s does not exist" % ",".join(usernames) ) return Transaction( type=3, version=cfg.txversion, asset={ "votes": votes }, )
def aslp2AddMeta(tkid, na, dt, ch=None): """ Build a aslp2 metadata edition transaction. Args: tkid (str): token id. na (str): name of the metadata info. dt (str): data of metadata. ch (int): chunk number. Returns: dposlib.ark.tx.Transaction: orphan transaction with appropriate aslp2 `vendorField`. """ args = dict(tokenid=tkid, name=na, data=dt) if ch: args["chunk"] = ch smartbridge = GET.api.vendor_aslp2_addmeta(**args) if smartbridge.pop("status", 0) != 200: raise Exception(smartbridge.get("error", "aslp smartbridge error")) return Transaction(typeGroup=1, type=0, amount=1, recipientId=cfg.master_address, vendorField=json.dumps(smartbridge, separators=(",", ":")))
def entityUpdate(registrationId, ipfsData, name=None): """ Build an entity update. Arguments: registrationId (str): registration id ipfsData (base58): ipfs DAG. Default to None. name (str, optional): entity name Returns: dposlib.ark.tx.Transaction: orphan transaction. """ asset = rest.GET.api.transactions( registrationId ).get("data", {}).get("asset", {}) asset["action"] = 1 asset["registrationId"] = registrationId asset["data"] = { "ipfsData": ipfsData.decode("utf-8") if isinstance(ipfsData, bytes) else ipfsData } if name is not None: asset["data"]["name"] = name return Transaction( version=rest.cfg.txversion, typeGroup=2, type=6, asset=asset )
def nftRegisterCollection(name, desc, supply, schema, *issuers, **meta): """ Build a NFT collection registration transaction. Args: name (str): NFT name. desc (str): NFT description. supply (int): NFT maximum supply. schema (dict): NFT json schema. issuers (*args): list of public keys allowed to issue the NFT. meta (**kwargs): NFT metadata. Returns: dposlib.ark.tx.Transaction: orphan transaction. """ asset = { "nftCollection": { "name": name, "description": desc, "maximumSupply": min(1, supply), "jsonSchema": dict(schema) } } if meta: asset["nftCollection"]["metadata"] = meta if issuers: asset["nftCollection"]["allowedIssuers"] = list(issuers) return Transaction(typeGroup=9000, type=0, asset=asset)
def multiPayment(*pairs, **kwargs): """ Build multi-payment transaction. Emoji can be included in transaction vendorField using unicode formating. ```python >>> u"message with sparkles \u2728" ``` Args: pairs (iterable): recipient-amount pair iterable. vendorField (str): vendor field message. Returns: dposlib.ark.tx.Transaction: orphan transaction. """ return Transaction( version=cfg.txversion, type=6, vendorField=kwargs.get("vendorField", None), asset={ "payments": [ {"amount": int(a*100000000), "recipientId": r} for a, r in pairs ] } )
def registerMultiSignature(minSig, *publicKeys): """ Build a multisignature registration transaction. Args: minSig (int): minimum signature required. publicKeys (list of str): public key list. Returns: dposlib.ark.tx.Transaction: orphan transaction. """ return Transaction( version=cfg.txversion, type=4, MultiSignatureAddress=crypto.getAddress( crypto.getMultiSignaturePublicKey( minSig, *publicKeys ) ), asset={ "multiSignature": { "min": minSig, "publicKeys": publicKeys } }, signatures=[] )
def aslpSend(address, tkid, qt, no=None): """ Build a aslp1 send transaction. Args: address (str): recipient wallet address. tkid (str): token id. qt (int): quantity to burn. no (str): token notes. Returns: dposlib.ark.tx.Transaction: orphan transaction with appropriate aslp1 `vendorField`. """ args = dict(tokenid=tkid, quantity=qt) if no: args["notes"] = no[:32] smartbridge = GET.api.vendor_aslp1_send(**args) if smartbridge.pop("status", 0) != 200: raise Exception(smartbridge.get("error", "aslp smartbridge error")) return Transaction(typeGroup=1, type=0, amount=1, recipientId=address, vendorField=json.dumps(smartbridge, separators=(",", ":")))
def delegateResignation(): """ Build a delegate resignation transaction. Returns: dposlib.ark.tx.Transaction: orphan transaction. """ return Transaction( version=cfg.txversion, type=7 )
def nftBurn(txid): """ Build a NFT burn transaction. Args: txid (str): NFT mint transaction id. Returns: dposlib.ark.tx.Transaction: orphan transaction. """ return Transaction(typeGroup=9000, type=3, asset={"nftBurn": { "nftId": txid }})
def registerIpfs(ipfs): """ Build an IPFS registration transaction. Args: ipfs (str): ipfs DAG. Returns: dposlib.ark.tx.Transaction: orphan transaction. """ return Transaction( version=cfg.txversion, type=5, asset={ "ipfs": ipfs } )
def nftTransfer(address, *ids): """ Build a NFT transfer transaction. Args: address (str): recipient address. ids (list): list of NFT id to send (maximum=10). Returns: dposlib.ark.tx.Transaction: orphan transaction. """ return Transaction( typeGroup=9000, type=2, asset={"nftTransfer": { "nftIds": ids[:10], "recipientId": address, }})
def htlcRefund(txid): """ Build an HTLC refund transaction. Args: txid (str): htlc lock transaction id. Returns: dposlib.ark.tx.Transaction: orphan transaction. """ return Transaction( version=cfg.txversion, type=10, asset={ "refund": { "lockTransactionId": txid, } } )
def registerAsDelegate(username): """ Build a delegate registration transaction. Args: username (str): delegate username. Returns: dposlib.ark.tx.Transaction: orphan transaction. """ return Transaction( type=2, version=cfg.txversion, asset={ "delegate": { "username": username } } )
def registerSecondPublicKey(secondPublicKey): """ Build a second secret registration transaction. *You must own the secret issuing secondPublicKey* Args: secondPublicKey (str): public key as hex string. Returns: dposlib.ark.tx.Transaction: orphan transaction. """ return Transaction( type=1, version=cfg.txversion, asset={ "signature": { "publicKey": secondPublicKey } } )
def htlcClaim(txid, secret): """ Build an HTLC claim transaction. Args: txid (str): htlc lock transaction id. secret (str): passphrase used by htlc lock transaction. Returns: dposlib.ark.tx.Transaction: orphan transaction. """ return Transaction( version=cfg.txversion, type=9, asset={ "claim": { "lockTransactionId": txid, "unlockSecret": htlcSecret(secret) } } )
def aslpGenesis(de, sy, na, qt, du=None, no=None, pa=False, mi=False): """ Build a aslp1 genesis transaction. Args: de (int): decimal number. sy (str): token symbol. na (str): token name. qt (int): maximum supply. du (str): document URI. no (str): token notes. pa (bool): pausable token ? mi (bool): mintable token ? Returns: dposlib.ark.tx.Transaction: orphan transaction with appropriate aslp1 `vendorField`. """ args = dict(decimals=de, symbol=sy, name=na, quantity=qt) if du: args["uri"] = du if no: args["notes"] = no[:32] if pa: args["pausable"] = "true" if mi: args["mintable"] = "true" smartbridge = GET.api.vendor_aslp1_genesis(**args) if smartbridge.pop("status", 0) != 200: raise Exception(smartbridge.get("error", "aslp smartbridge error")) return Transaction(typeGroup=1, type=0, amount=100000000, recipientId=cfg.master_address, vendorField=json.dumps(smartbridge, separators=(",", ":")))
def nftCreate(collectionId, attributes, address=None): """ Build a NFT mint transaction. Args: collectionId (str): NFT collection id. attributes (dict): NFT attributes matching defined schema. address (str): recipient address. Returns: dposlib.ark.tx.Transaction: orphan transaction. """ asset = { "nftToken": { "collectionId": collectionId, "attributes": dict(attributes) } } if address is not None: asset["nftToken"]["recipientId"] = address return Transaction(typeGroup=9000, type=1, asset=asset)
def htlcLock(amount, address, secret, expiration=24, vendorField=None): """ Build an HTLC lock transaction. Emoji can be included in transaction vendorField using unicode formating. ```python >>> vendorField = u"message with sparkles \u2728" ``` Args: amount (float): transaction amount in ark. address (str): valid recipient address. secret (str): lock passphrase. expiration (float): transaction validity in hour. vendorField (str): vendor field message. Returns: dposlib.ark.tx.Transaction: orphan transaction. """ return Transaction( version=cfg.txversion, type=8, amount=amount*100000000, recipientId=address, vendorField=vendorField, asset={ "lock": { "secretHash": hexlify( hashlib.sha256(htlcSecret(secret).encode("utf-8")).digest() ), "expiration": { "type": 1, "value": int(slots.getTime() + expiration*60*60) } } } )
def entityResign(registrationId): """ Build an entity resignation. Arguments: registrationId (str): registration id Returns: dposlib.ark.tx.Transaction: orphan transaction. """ asset = rest.GET.api.transactions( registrationId ).get("data", {}).get("asset", {}) asset["action"] = 2 asset["registrationId"] = registrationId asset["data"] = {} return Transaction( version=rest.cfg.txversion, typeGroup=2, type=6, asset=asset )
def aslp2VoidMeta(tkid, tx): """ Build a aslp2 metadata cleaning transaction. Args: tkid (str): token id. tx (str): transaction id of metadata to void. Returns: dposlib.ark.tx.Transaction: orphan transaction with appropriate aslp2 `vendorField`. """ args = dict(tokenid=tkid, txid=tx) smartbridge = GET.api.vendor_aslp2_voidmeta(**args) if smartbridge.pop("status", 0) != 200: raise Exception(smartbridge.get("error", "aslp smartbridge error")) return Transaction(typeGroup=1, type=0, amount=1, recipientId=cfg.master_address, vendorField=json.dumps(smartbridge, separators=(",", ":")))
def entityRegister(name, type="business", subtype=0, ipfsData=None): """ Build an entity registration. Arguments: name (str): entity name type (str): entity type. Possible values are `business`, `product`, `plugin`, `module` and `delegate`. Default to `business`. subtype (int): entity subtype ipfsData (base58): ipfs DAG. Default to None. Returns: dposlib.ark.tx.Transaction: orphan transaction. """ asset = { "type": MAGISTRATE[type], "subType": subtype, "action": 0, "data": { "name": name.decode("utf-8") if isinstance(name, bytes) else name, } } if ipfsData is not None: asset["data"]["ipfsData"] = \ ipfsData.decode("utf-8") if isinstance(ipfsData, bytes) \ else ipfsData return Transaction( version=rest.cfg.txversion, typeGroup=2, type=6, asset=asset )
def init(seed=None): """ Blockchain initialisation. It stores root values in `cfg` module. """ global DAEMON_PEERS NETWORK = getattr(cfg, "network", "dark") # configure cold package path and fils according to installation if ".zip" in __file__ or ".egg" in __file__: # --> module loaded from zip or egg file path_module = os.path.join(HOME, NETWORK + ".py") package_path = NETWORK else: # --> module loaded from python package path_module = os.path.join(os.path.join(__path__[0], "cold"), NETWORK + ".py") package_path = __package__ + ".cold." + NETWORK path_module = os.path.normpath(path_module) # if network connection available if getattr(cfg, "hotmode", True): CONFIG = rest.GET.api.node.configuration(peer=seed) # nethash must be added before next api endpoint call cfg.headers["nethash"] = CONFIG["data"]["nethash"] FEES = rest.GET.api.node.fees(peer=seed) # write configuration in python module, overriding former one _write_module(path_module, CONFIG, FEES) else: # remove cold package if hasattr(sys.modules[__package__], "cold"): del sys.modules[__package__].cold # load cold package try: sys.modules[__package__].cold = import_module(package_path) CONFIG = sys.modules[__package__].cold.configuration FEES = sys.modules[__package__].cold.fees except Exception: CONFIG = FEES = {} # no network connetcion neither local configuration files if "data" not in CONFIG: raise Exception("no data available") data = CONFIG.get("data", {}) constants = data["constants"] # -- root configuration --------------------------------------------------- cfg.version = data.get("core", {}).get("version", "?") cfg.explorer = data["explorer"] cfg.marker = "%x" % data["version"] cfg.pubkeyHash = data["version"] cfg.token = data["token"] cfg.symbol = data["symbol"] cfg.ports = dict([k.split("/")[-1], v] for k, v in data["ports"].items()) cfg.activeDelegates = constants["activeDelegates"] cfg.maxTransactions = constants["block"]["maxTransactions"] cfg.blocktime = constants["blocktime"] cfg.begintime = pytz.utc.localize( datetime.strptime(constants["epoch"], "%Y-%m-%dT%H:%M:%S.000Z")) cfg.blockreward = float(constants["reward"]) / 100000000 # since ark v2.4 wif and slip44 are provided by network if "wif" in data: cfg.wif = "%x" % data["wif"] if "slip44" in data: cfg.slip44 = str(data["slip44"]) # -- static fee management ------------------------------------------------ cfg.fees = constants.get("fees", {}) # -- dynamic fee management ----------------------------------------------- # since v2.1 dynamicFees offsets are in "transactionPool" field cfg.doffsets = data.get("transactionPool", {}).get("dynamicFees", {}).get("addonBytes", {}) # since ark v2.4 fee statistics moved to ~/api/node/fees endpoint # since ark v2.6 fee statistic structure is a dictionary setattr(cfg, "feestats", FEES["data"]) # activate dynamic fees Transaction.useDynamicFee("avgFee") # -- network connection management ---------------------------------------- # change peers every 30 seconds if getattr(cfg, "hotmode", False): DAEMON_PEERS = setInterval(30)(_select_peers)() return True