"""
pyacryl2.utils.address
~~~~~~~~~~~~~~~~~~~~~~
Acryl address
"""
import base64
import json
import math
import struct
import time
from functools import wraps
import base58
from pyacryl2.client import DEFAULT_NODE_ADDRESS, AcrylClient, CHAIN_ID_NAMES
from pyacryl2.utils.crypto import sign_with_private_key
DEFAULT_ADDRESS_VERSION = 1
DEFAULT_TRANSFER_TRANSACTION_FEE = 100000
DEFAULT_LEASE_TRANSACTION_FEE = 100000
DEFAULT_ALIAS_TRANSACTION_FEE = 100000
DEFAULT_ISSUE_TRANSACTION_FEE = 100000000
DEFAULT_REISSUE_TRANSACTION_FEE = 100000000
DEFAULT_BURN_TRANSACTION_FEE = 100000
DEFAULT_MASS_TRANSFER_TRANSACTION_FEE = 100000
DEFAULT_CANCEL_LEASE_TRANSACTION_FEE = 100000
DEFAULT_SPONSORSHIP_TRANSACTION_FEE = 100000000
DEFAULT_SET_SCRIPT_TRANSACTION_FEE = 1000000
DEFAULT_SET_ASSET_SCRIPT_TRANSACTION_FEE = 100000000
DEFAULT_DATA_TRANSACTION_FEE_MULTIPLICATOR = 1000000
TRANSACTION_TYPE_GENESIS = 1
TRANSACTION_TYPE_PAYMENT = 2
TRANSACTION_TYPE_ISSUE = 3
TRANSACTION_TYPE_TRANSFER = 4
TRANSACTION_TYPE_REISSUE = 5
TRANSACTION_TYPE_BURN = 6
TRANSACTION_TYPE_EXCHANGE = 7
TRANSACTION_TYPE_LEASE = 8
TRANSACTION_TYPE_CANCEL_LEASE = 9
TRANSACTION_TYPE_ALIAS = 10
TRANSACTION_TYPE_MASS_TRANSFER = 11
TRANSACTION_TYPE_DATA = 12
TRANSACTION_TYPE_SET_SCRIPT = 13
TRANSACTION_TYPE_SPONSORSHIP = 14
TRANSACTION_TYPE_SET_ASSET_SCRIPT = 15
TRANSACTION_TYPE_INVOKE_SCRIPT = 16
DATA_TRANSACTION_INT_TYPE = 0
DATA_TRANSACTION_BOOLEAN_TYPE = 1
DATA_TRANSACTION_STRING_TYPE = 2
DATA_TRANSACTION_BINARY_TYPE = 3
DEFAULT_TRANSACTION_VERSION = 1
[docs]def sign_required(method):
"""
Decorator. Check if address can sign request data, if not then raises ValueError
:param method: address class method
:return: wrapped method
:rtype: Callable
:raises: ValueError
"""
@wraps(method)
def wrapper(*args, **kwargs):
if not args[0].can_sign:
raise ValueError("Can't sign request: address has not private key")
return method(*args, **kwargs)
return wrapper
[docs]class BaseAcrylAddress:
"""
Base address class. Has methods for transaction data generation, common for child address classes
:param value: address text value in base58
:param private_key: address private key string in base58
:param public_key: address public key string in base58
:param address_seed: address seed
:param chain_id: address chain id
:param nonce: nonce
:param node_address: node API address for data retrieve and transaction broadcast
:param version: address version (currently, only for information)
:param online: make requests or return only request data
:param client_request_params: client API request param (check API client doc)
"""
def __init__(self, value=None, private_key=None, public_key=None, address_seed=None, chain_id=None, nonce=0,
node_address=DEFAULT_NODE_ADDRESS, version=DEFAULT_ADDRESS_VERSION, online=True,
client_request_params=None):
self.value = value
self.private_key = private_key
self.public_key = public_key
self.seed = address_seed
self.chain_id = chain_id
if not self.chain_id and self.value:
self.chain_id = chr(base58.b58decode(self.value)[1])
self.nonce = nonce
self.node_address = node_address
self.version = version
self.online = online
self.client_request_params = client_request_params
self._api_client = None
[docs] def save_as_json(self, file_path, encode_seed=False):
"""
Save address data as json
:param file_path: file path
:param encode_seed: encode seed to base58
:return: nothing
:rtype: None
"""
file_data = {
"address": self.value, "private_key": self.private_key, "public_key": self.public_key,
"seed": base58.b58encode(self.seed).decode() if encode_seed else self.seed, "chain_id": self.chain_id
}
with open(file_path, 'w') as json_file:
json.dump(file_data, json_file)
[docs] def load_from_json(self, file_path, decode_seed=False):
"""
Get address data from json file
:param file_path: file path
:param decode_seed: decode seed from base58
:return: nothing
:rtype: None
"""
with open(file_path, 'r') as json_file:
file_data = json.load(json_file)
self.value = file_data.get('address')
self.private_key = file_data.get('private_key')
self.public_key = file_data.get('public_key')
self.seed = file_data.get('seed')
if self.seed and decode_seed:
self.seed = base58.b58decode(self.seed)
self.chain_id = file_data.get('chain_id')
def _generate_asset_sponsorship_transaction(self, asset_id, min_sponsored_asset_fee, transaction_fee, timestamp):
"""
Prepare data for sponsorship transaction
:param asset_id:
:param min_sponsored_asset_fee:
:param transaction_fee:
:param timestamp:
:return:
"""
if timestamp == 0:
timestamp_param = int(time.time() * 1000)
else:
timestamp_param = timestamp
version = 1
sign_data = [
TRANSACTION_TYPE_SPONSORSHIP.to_bytes(1, 'big'),
version.to_bytes(1, 'big'),
base58.b58decode(self.public_key),
base58.b58decode(asset_id),
struct.pack(">Q", min_sponsored_asset_fee),
struct.pack(">Q", transaction_fee),
struct.pack(">Q", timestamp_param),
]
signature = sign_with_private_key(self.private_key, b''.join(sign_data))
transaction_data = {
"type": TRANSACTION_TYPE_SPONSORSHIP,
"version": version,
"senderPublicKey": self.public_key,
"assetId": asset_id,
"fee": transaction_fee,
"timestamp": timestamp_param,
"minSponsoredAssetFee": min_sponsored_asset_fee,
"proofs": [signature]
}
return transaction_data
def _generate_alias_transaction(self, alias, transaction_fee, timestamp):
"""
Prepare data for alias transaction
:return:
"""
if timestamp == 0:
timestamp_param = int(time.time() * 1000)
else:
timestamp_param = timestamp
alias_data = b''.join((
b'\x02', self.chain_id.encode('latin-1'), struct.pack(">H", len(alias)), alias.encode('latin-1')
))
sign_data = [
TRANSACTION_TYPE_ALIAS.to_bytes(1, 'big'),
base58.b58decode(self.public_key),
struct.pack(">H", len(alias_data)),
alias_data,
struct.pack(">Q", transaction_fee),
struct.pack(">Q", timestamp_param),
]
signature = sign_with_private_key(self.private_key, b''.join(sign_data))
transaction_data = {
"senderPublicKey": self.public_key,
"alias": alias,
"fee": transaction_fee,
"timestamp": timestamp_param,
"signature": signature,
}
return transaction_data
def _generate_transfer_transaction(self, recipient, asset_id, fee_asset_id, amount, attachment, transaction_fee,
timestamp):
"""
Prepare data for transfer transaction
:param recipient:
:param amount:
:param attachment:
:param transaction_fee:
:param timestamp:
:return:
"""
if isinstance(recipient, AcrylAddress):
recipient_address = recipient.value
else:
recipient_address = recipient
if timestamp == 0:
timestamp_param = int(time.time() * 1000)
else:
timestamp_param = timestamp
if not attachment:
encoded_attachment = b''
else:
encoded_attachment = attachment.encode('latin-1')
if asset_id:
asset_sign_data = b'\1%s' % base58.b58decode(asset_id)
else:
asset_sign_data = b'\0'
if fee_asset_id:
fee_asset_sign_data = b'\1%s' % base58.b58decode(fee_asset_id)
else:
fee_asset_sign_data = b'\0'
sign_data = [
TRANSACTION_TYPE_TRANSFER.to_bytes(1, 'big'),
base58.b58decode(self.public_key),
asset_sign_data,
fee_asset_sign_data,
struct.pack(">Q", timestamp_param),
struct.pack(">Q", amount),
struct.pack(">Q", transaction_fee),
base58.b58decode(recipient_address),
struct.pack(">H", len(b'' or encoded_attachment)),
encoded_attachment
]
signature = sign_with_private_key(self.private_key, b''.join(sign_data))
transaction_data = {
"senderPublicKey": self.public_key,
"recipient": recipient_address,
"amount": amount,
"fee": transaction_fee,
"timestamp": timestamp_param,
"attachment": base58.b58encode(encoded_attachment).decode(),
"signature": signature,
}
if asset_id:
transaction_data["assetId"] = asset_id
if fee_asset_id:
transaction_data["feeAssetId"] = fee_asset_id
return transaction_data
def _generate_asset_issue_transaction(self, name, description, quantity, decimals, reissuable, transaction_fee,
script, version, timestamp):
"""
Prepare asset issue transaction data
:param name:
:param description:
:param quantity:
:param decimals:
:param reissuable:
:param version
:param timestamp:
:return:
"""
if not timestamp:
timestamp_param = int(time.time() * 1000)
else:
timestamp_param = timestamp
sign_data = [
TRANSACTION_TYPE_ISSUE.to_bytes(1, 'big'),
base58.b58decode(self.public_key),
struct.pack(">H", len(name)),
name.encode('latin-1'),
struct.pack(">H", len(description)),
description.encode('latin-1'),
struct.pack(">Q", quantity),
struct.pack(">B", decimals),
reissuable.to_bytes(1, 'big'),
struct.pack(">Q", transaction_fee),
struct.pack(">Q", timestamp_param)
]
transaction_data = {
"senderPublicKey": self.public_key,
"name": name,
"quantity": quantity,
"timestamp": timestamp_param,
"description": description,
"decimals": decimals,
"reissuable": reissuable,
"fee": transaction_fee,
}
if version > 1:
sign_data.insert(1, version.to_bytes(1, 'big'))
sign_data.insert(2, self.chain_id.encode('latin-1'))
transaction_data.update({
"type": TRANSACTION_TYPE_ISSUE,
"senderPublicKey": self.public_key,
"version": version,
"chainId": self.chain_id
})
if script:
if version < 2:
raise ValueError("Smart assets require at least 2 transaction version")
compiled_script = base64.b64decode(script)
sign_data.extend([
b'\1', # smart asset
struct.pack(">H", len(compiled_script)),
compiled_script
])
transaction_data["script"] = 'base64:' + script
else:
if version >= 2:
sign_data.append(b'\0')
signature = sign_with_private_key(self.private_key, b''.join(sign_data))
if version == 1:
transaction_data["signature"] = signature
else:
transaction_data["proofs"] = [signature]
return transaction_data
def _generate_asset_reissue_transaction(self, asset_id, quantity, reissuable, transaction_fee, timestamp):
"""
Prepare asset reissue transaction data
:param asset_id:
:param quantity:
:param reissuable:
:param timestamp:
:return:
"""
if timestamp == 0:
timestamp_param = int(time.time() * 1000)
else:
timestamp_param = timestamp
sign_data = [
TRANSACTION_TYPE_REISSUE.to_bytes(1, 'big'),
base58.b58decode(self.public_key),
base58.b58decode(asset_id),
struct.pack(">Q", quantity),
reissuable.to_bytes(1, 'big'),
struct.pack(">Q", transaction_fee),
struct.pack(">Q", timestamp_param)
]
signature = sign_with_private_key(self.private_key, b''.join(sign_data))
transaction_data = {
"senderPublicKey": self.public_key,
"assetId": asset_id,
"quantity": quantity,
"timestamp": timestamp_param,
"reissuable": reissuable,
"fee": transaction_fee,
"signature": signature
}
return transaction_data
def _generate_asset_burn_transaction(self, asset_id, quantity, transaction_fee, timestamp):
"""
Prepare asset reissue transaction data
:param asset_id:
:param quantity:
:param reissuable:
:param timestamp:
:return:
"""
if timestamp == 0:
timestamp_param = int(time.time() * 1000)
else:
timestamp_param = timestamp
sign_data = [
TRANSACTION_TYPE_BURN.to_bytes(1, 'big'),
base58.b58decode(self.public_key),
base58.b58decode(asset_id),
struct.pack(">Q", quantity),
struct.pack(">Q", transaction_fee),
struct.pack(">Q", timestamp_param)
]
signature = sign_with_private_key(self.private_key, b''.join(sign_data))
transaction_data = {
"senderPublicKey": self.public_key,
"assetId": asset_id,
"quantity": quantity,
"timestamp": timestamp_param,
"fee": transaction_fee,
"signature": signature
}
return transaction_data
def _generate_data_transaction(self, data, fee=0, version=1, timestamp=0):
"""
Prepare data for data transaction
:return:
"""
if not timestamp:
timestamp_param = int(time.time() * 1000)
else:
timestamp_param = timestamp
data_buffer = []
for item in data:
key_encoded = item['key'].encode('latin-1')
data_buffer.extend([struct.pack(">H", len(key_encoded)), key_encoded])
if item['type'] == 'integer':
item_value = [
DATA_TRANSACTION_INT_TYPE.to_bytes(1, 'big'),
struct.pack(">Q", item['value'])
]
elif item['type'] == 'boolean':
item_value = [
DATA_TRANSACTION_BOOLEAN_TYPE.to_bytes(1, 'big'),
item['value'].to_bytes(1, 'big')
]
elif item['type'] == 'binary':
item_value = [
DATA_TRANSACTION_STRING_TYPE.to_bytes(1, 'big'),
struct.pack(">H", len(item['value'])),
item['value']
]
item['value'] = "base64:" + base64.b64encode(item['value']).decode('latin-1')
elif item['type'] == 'string':
item_value = [
DATA_TRANSACTION_BINARY_TYPE.to_bytes(1, 'big'),
struct.pack(">H", len(item['value'])),
item['value'].encode('latin-1')
]
else:
raise ValueError("Unknown data type: '{}'".format(item['type']))
data_buffer.extend(item_value)
if not fee:
transaction_fee = int(math.floor(1 + (len(json.dumps(data)) + 8 - 1) / 1024) *
DEFAULT_DATA_TRANSACTION_FEE_MULTIPLICATOR)
else:
transaction_fee = fee
sign_data = [
TRANSACTION_TYPE_DATA.to_bytes(1, 'big'),
version.to_bytes(1, 'big'),
base58.b58decode(self.public_key),
struct.pack(">H", len(data)),
b''.join(data_buffer),
struct.pack(">Q", timestamp_param),
struct.pack(">Q", transaction_fee),
]
transaction_data = {
"type": TRANSACTION_TYPE_DATA,
"version": version,
"senderPublicKey": self.public_key,
"data": data,
"fee": transaction_fee,
"timestamp": timestamp_param,
"proofs": [sign_with_private_key(self.private_key, b''.join(sign_data))]
}
return transaction_data
def _generate_lease_transaction(self, recipient, amount, transaction_fee, timestamp):
"""
Prepare data for lease transaction
:param recipient:
:param amount:
:param transaction_fee:
:param timestamp:
:return:
"""
if isinstance(recipient, AcrylAddress):
recipient_address = recipient.value
else:
recipient_address = recipient
if timestamp == 0:
timestamp_param = int(time.time() * 1000)
else:
timestamp_param = timestamp
sign_data = [
TRANSACTION_TYPE_LEASE.to_bytes(1, 'big'),
base58.b58decode(self.public_key),
base58.b58decode(recipient_address),
struct.pack(">Q", amount),
struct.pack(">Q", transaction_fee),
struct.pack(">Q", timestamp_param),
]
signature = sign_with_private_key(self.private_key, b''.join(sign_data))
transaction_data = {
"senderPublicKey": self.public_key,
"recipient": recipient_address,
"amount": amount,
"fee": transaction_fee,
"timestamp": timestamp_param,
"signature": signature
}
return transaction_data
def _generate_cancel_lease_transaction(self, transaction_id, transaction_fee, timestamp):
"""
Prepare data for cancel lease transaction
:param transaction_id:
:param transaction_fee:
:param timestamp:
:return:
"""
if timestamp == 0:
timestamp_param = int(time.time() * 1000)
else:
timestamp_param = timestamp
sign_data = [
TRANSACTION_TYPE_CANCEL_LEASE.to_bytes(1, 'big'),
base58.b58decode(self.public_key),
struct.pack(">Q", transaction_fee),
struct.pack(">Q", timestamp_param),
base58.b58decode(transaction_id),
]
signature = sign_with_private_key(self.private_key, b''.join(sign_data))
transaction_data = {
"senderPublicKey": self.public_key,
"txId": transaction_id,
"fee": transaction_fee,
"timestamp": timestamp_param,
"signature": signature
}
return transaction_data
def _generate_mass_transfer_transaction(self, transfer_data, asset_id, attachment, version, timestamp):
"""
Setup mass transfer transaction data
:param transfer_data:
:param attachment:
:param timestamp:
:return:
"""
if not timestamp:
timestamp_param = int(time.time() * 1000)
else:
timestamp_param = timestamp
if not attachment:
encoded_attachment = b''
else:
encoded_attachment = attachment.encode('latin-1')
mass_fee = 100000 + math.ceil(0.5 * len(transfer_data)) * 100000
recipients_sign_data = []
for recipient_data in transfer_data:
recipients_sign_data.append(base58.b58decode(recipient_data['recipient']))
recipients_sign_data.append(struct.pack(">Q", recipient_data['amount']))
sign_data = [
TRANSACTION_TYPE_MASS_TRANSFER.to_bytes(1, 'big'),
version.to_bytes(1, 'big'),
base58.b58decode(self.public_key),
b'\0', # for default asset (Acryl)
struct.pack(">H", len(transfer_data)),
b''.join(recipients_sign_data),
struct.pack(">Q", timestamp_param),
struct.pack(">Q", mass_fee),
struct.pack(">H", len(encoded_attachment)),
encoded_attachment
]
if asset_id:
sign_data[3] = b'\1'
sign_data.insert(4, base58.b58decode(asset_id))
signature = sign_with_private_key(self.private_key, b''.join(sign_data))
transaction_data = {
"type": TRANSACTION_TYPE_MASS_TRANSFER,
"version": 1,
"assetId": asset_id or "",
"senderPublicKey": self.public_key,
"fee": mass_fee,
"timestamp": timestamp_param,
"transfers": transfer_data,
"attachment": base58.b58encode(encoded_attachment).decode(),
"signature": signature,
"proofs": [
signature
]
}
return transaction_data
def _generate_set_script_transaction(self, script, transaction_fee, timestamp, version):
"""
Generate set script transaction data
:param script:
:param transaction_fee:
:return:
"""
if not timestamp:
timestamp_param = int(time.time() * 1000)
else:
timestamp_param = timestamp
script_bytes = base64.b64decode(script)
sign_data = [
TRANSACTION_TYPE_SET_SCRIPT.to_bytes(1, 'big'),
version.to_bytes(1, 'big'),
self.chain_id.encode('latin-1'),
base58.b58decode(self.public_key),
b'\1',
struct.pack(">H", len(script_bytes)),
script_bytes,
struct.pack(">Q", transaction_fee),
struct.pack(">Q", timestamp_param),
]
signature = sign_with_private_key(self.private_key, b''.join(sign_data))
transaction_data = {
"type": TRANSACTION_TYPE_SET_SCRIPT,
"version": version,
"senderPublicKey": self.public_key,
"fee": transaction_fee,
"timestamp": timestamp_param,
"script": 'base64:' + script,
"proofs": [signature]
}
return transaction_data
def _generate_set_asset_script_transaction(self, script, asset_id, transaction_fee, timestamp, version):
"""
Generate set script transaction data
:param asset_id:
:param script:
:param transaction_fee:
:return:
"""
if not timestamp:
timestamp_param = int(time.time() * 1000)
else:
timestamp_param = timestamp
script_bytes = base64.b64decode(script)
sign_data = [
TRANSACTION_TYPE_SET_ASSET_SCRIPT.to_bytes(1, 'big'),
version.to_bytes(1, 'big'),
self.chain_id.encode('latin-1'),
base58.b58decode(self.public_key),
base58.b58decode(asset_id),
struct.pack(">Q", transaction_fee),
struct.pack(">Q", timestamp_param),
b'\1',
struct.pack(">H", len(script_bytes)),
script_bytes,
]
signature = sign_with_private_key(self.private_key, b''.join(sign_data))
transaction_data = {
"type": TRANSACTION_TYPE_SET_ASSET_SCRIPT,
"version": version,
"assetId": asset_id,
"senderPublicKey": self.public_key,
"fee": transaction_fee,
"timestamp": timestamp_param,
"script": 'base64:' + script,
"proofs": [signature]
}
return transaction_data
@property
def can_sign(self):
"""
Ability to sign requests
:return: yes or no
:rtype: bool
"""
return bool(self.private_key)
@property
def chain(self):
"""
Address chain name
:return: chain name
:rtype: str
"""
chains_dict = dict(CHAIN_ID_NAMES)
return chains_dict[self.chain_id]
@property
def client(self):
"""
Current API client instance
:return: API client instance
"""
return self._api_client
@property
def base58_seed(self):
"""
Seed encoded base58
:return: seed in base58
:rtype: bytes
"""
return base58.b58encode(self.seed.encode('latin-1')).decode()
[docs]class AcrylAddress(BaseAcrylAddress):
"""
Acryl address class. Simplifies transaction data generation and data requests
:param value: address text value in base58
:param private_key: address private key string in base58
:param public_key: address public key string in base58
:param address_seed: address seed
:param chain_id: address chain id
:param nonce: nonce
"""
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self._api_client = AcrylClient(
node_address=self.node_address, chain_id=self.chain_id, online=self.online,
request_params=self.client_request_params
)
[docs] def from_alias(self, alias):
"""
Set address value from alias
:param alias: alias of address
:return: address object with address value
"""
address_data = self._api_client.alias_by_alias(alias)
address_bytes = base58.b58decode(address_data["address"])
self.value = address_data["address"]
self.private_key = None
self.public_key = None
self.seed = None
self.chain_id = chr(address_bytes[1])
self.nonce = None
self.version = int(address_bytes[0])
[docs] def get_balance(self):
"""
Get address balance
:return: balance value
:rtype: int or dict
"""
data = self._api_client.address_balance(self.value)
if not self.online:
return data
return data["balance"]
[docs] def get_effective_balance(self):
"""
Get address effective balance
:return: balance value
:rtype: int or dict
"""
data = self._api_client.address_effective_balance(self.value)
if not self.online:
return data
return data["balance"]
[docs] def get_confirmed_balance(self, confirmations):
"""
Get address balance
:return: balance value
:rtype: int or dict
"""
data = self._api_client.address_balance_confirmed(self.value, confirmations)
if not self.online:
return data
return data["balance"]
[docs] def get_assets(self):
"""
Get address assets
:return: asset balances in dict
:rtype: int or dict
"""
data = self._api_client.assets_balance(self.value)
if not self.online:
return data
return data["balances"]
[docs] def get_address_data(self):
"""
Get address data from blockchain
:return: data in dict
:rtype: dict
"""
data = self._api_client.address_data_address(self.value)
if not self.online:
return data
return data
[docs] def get_aliases(self, flat=True):
"""
Get address aliases
:param flat: get only alias names without chain ids
:return: list of dicts with prefix, chain ids and alias names or only alias names
:rtype: list or dict
"""
aliases = []
data = self._api_client.alias_by_address(self.value)
if not self.online:
return data
for alias_data_string in data.response_data:
prefix, chain_id, alias = alias_data_string.split(":")
if flat:
aliases.append(alias)
else:
aliases.append({"chain_id": chain_id, "alias": alias, "prefix": prefix})
return aliases
[docs] def validate(self):
"""
Validate address
:return:
:rtype bool or dict
"""
data = self._api_client.address_validate(self.value)
if not self.online:
return data
return data["valid"]
[docs] def get_address_info(self):
"""
Collect address info (balances, assets, data)
:return: address info dict
:rtype: dict
"""
address_info = dict()
address_info["valid"] = self.validate()
if not address_info["valid"]:
return address_info
address_info["balance"] = self.get_balance()
address_info["effective_balance"] = self.get_effective_balance()
address_info["assets"] = self.get_assets()
address_info["address_data"] = self.get_address_data()
return address_info
[docs] @sign_required
def data_transaction(self, data, fee=0, version=DEFAULT_TRANSACTION_VERSION, timestamp=0):
"""
Create data transaction
:param data: data for data transaction (list of dicts with keys type, key, value)
Suitable python types for transaction data types:
- boolean - `bool`
- binary - `bytes` (converts them to base64 string)
- integer - `int`
- string - `str`
:type data: list
:param version: data transaction version
:type fee: int
:param fee: transaction fee. 1000000 is minimum.
:type version: int
:param timestamp: transaction timestamp
:type timestamp: int
:return: client request result
:rtype: AcrylClientResponse or dict
"""
transaction_data = self._generate_data_transaction(data, fee, version, timestamp)
result = self._api_client.transaction_broadcast(transaction_data)
return result
[docs] @sign_required
def transfer_acryl(self, recipient, amount, attachment=None, transaction_fee=DEFAULT_TRANSFER_TRANSACTION_FEE,
timestamp=0):
"""
Send acryl to address
:param recipient: recipient address in base58
:type recipient: str or AcrylAddress or AcrylAsyncAddress
:param amount: amount of acryl
:type amount: int
:param attachment: attachment string
:type attachment: str
:param transaction_fee: fee for transfer transaction
:type transaction_fee: int
:param timestamp: timestamp of transaction
:type timestamp: int
:return: transfer result
:rtype: AcrylClientResponse or dict
"""
transaction_data = self._generate_transfer_transaction(
recipient, None, None, amount, attachment, transaction_fee, timestamp
)
result = self._api_client.asset_broadcast_transfer(transaction_data)
return result
[docs] @sign_required
def transfer_asset(self, recipient, asset_id, fee_asset_id, amount, attachment=None,
transaction_fee=DEFAULT_TRANSFER_TRANSACTION_FEE, timestamp=0):
"""
Send asset to address. If asset_id or fee_asset_id is None then acryl will be used
:param recipient: recipient address in base58
:type recipient: str or AcrylAddress or AcrylAsyncAddress
:param asset_id: asset id
:type asset_id: str or None
:param fee_asset_id: fee asset id
:type fee_asset_id: str or None
:param amount: amount of acryl
:type amount: int
:param attachment: attachment string
:type attachment: str
:param transaction_fee: fee for transfer transaction
:type transaction_fee: int
:param timestamp: timestamp of transaction
:type timestamp: int
:return: transfer result
:rtype: AcrylClientResponse or dict
"""
transaction_data = self._generate_transfer_transaction(
recipient, asset_id, fee_asset_id, amount, attachment, transaction_fee, timestamp
)
result = self._api_client.asset_broadcast_transfer(transaction_data)
return result
[docs] @sign_required
def mass_transfer_acryl(self, transfer_data, attachment=None, timestamp=None):
"""
Mass transfer acryl
:param transfer_data: list of dicts with recipient and amount i.e.
`[{ 'recipient': '3N1xca2DY8AEwqRDAJpzUgY99eq8J9h4rB3', 'amount': 1000 }]`
:param attachment: transaction attachment
:param transaction_fee: mass transfer transaction fee
:param timestamp: transaction timestamp
:return:
:rtype: AcrylClientResponse or dict
"""
transaction_data = self._generate_mass_transfer_transaction(
transfer_data, None, attachment, DEFAULT_TRANSACTION_VERSION, timestamp)
result = self._api_client.transaction_broadcast(transaction_data)
return result
[docs] @sign_required
def mass_transfer_assets(self, transfer_data, asset_id=None, attachment=None, version=DEFAULT_TRANSACTION_VERSION,
timestamp=None):
"""
Mass transfer acryl
:param transfer_data: list of dicts with recipient and amount i.e.
`[{ 'recipient': '3N1xca2DY8AEwqRDAJpzUgY99eq8J9h4rB3', 'amount': 1000 }]`
:param attachment: transaction attachment
:param asset_id: ID of transferring asset
:param timestamp: transaction timestamp
:return:
"""
transaction_data = self._generate_mass_transfer_transaction(
transfer_data, asset_id, attachment, version, timestamp
)
result = self._api_client.transaction_broadcast(transaction_data)
return result
[docs] @sign_required
def lease_acryl(self, recipient, amount, transaction_fee=DEFAULT_LEASE_TRANSACTION_FEE, timestamp=0):
"""
Lease acryl to address
:param recipient:
:param amount:
:param transaction_fee:
:param timestamp:
:return:
"""
transaction_data = self._generate_lease_transaction(recipient, amount, transaction_fee, timestamp)
result = self._api_client.leasing_broadcast_lease(transaction_data)
return result
[docs] @sign_required
def lease_cancel(self, transaction_id, transaction_fee=DEFAULT_CANCEL_LEASE_TRANSACTION_FEE, timestamp=0):
"""
Cancel acryl lease
:param transaction_id:
:param transaction_fee:
:param timestamp:
:return:
"""
transaction_data = self._generate_cancel_lease_transaction(transaction_id, transaction_fee, timestamp)
result = self._api_client.leasing_broadcast_cancel_lease(transaction_data)
return result
[docs] @sign_required
def create_alias(self, alias, transaction_fee=DEFAULT_ALIAS_TRANSACTION_FEE, timestamp=0):
"""
Create alias for address
:param alias: alias (min 4, max 30 chars)
:param transaction_fee:
:param timestamp:
:return:
"""
transaction_data = self._generate_alias_transaction(alias, transaction_fee, timestamp)
result = self._api_client.alias_broadcast_create(transaction_data)
return result
[docs] @sign_required
def issue_asset(self, name, description, quantity, decimals, reissuable,
transaction_fee=DEFAULT_ISSUE_TRANSACTION_FEE, version=DEFAULT_TRANSACTION_VERSION, timestamp=0):
"""
Issue asset in acryl blockchain
:param name: asset name (min 4, max 16 chars)
:param description: asset description
:param quantity: asset quantity
:param decimals: asset decimals
:param reissuable: is asset reissuable
:param transaction_fee: asset issue transaction fee
:param version: transaction version
:param timestamp: transaction timestamp
:return:
"""
transaction_data = self._generate_asset_issue_transaction(
name, description, quantity, decimals, reissuable, transaction_fee, None, version, timestamp
)
if version == 1:
result = self._api_client.asset_broadcast_issue(transaction_data)
else:
result = self._api_client.transaction_broadcast(transaction_data)
return result
[docs] @sign_required
def issue_smart_asset(self, name, description, quantity, decimals, reissuable, script,
transaction_fee=DEFAULT_ISSUE_TRANSACTION_FEE, timestamp=0):
"""
Issue smart asset in acryl blockchain (asset with script)
:param name: asset name (min 4, max 16 chars)
:param description: asset description
:param quantity: asset quantity
:param decimals: asset decimals
:param reissuable: is asset reissuable
:param transaction_fee: asset issue transaction fee
:param timestamp: transaction timestamp
:return:
"""
transaction_data = self._generate_asset_issue_transaction(
name, description, quantity, decimals, reissuable, transaction_fee, script, 2, timestamp
)
result = self._api_client.transaction_broadcast(transaction_data)
return result
[docs] @sign_required
def reissue_asset(self, asset_id, quantity, reissuable, transaction_fee=DEFAULT_REISSUE_TRANSACTION_FEE,
timestamp=0):
"""
Reissue asset in acryl blockchain
:param asset_id: asset id
:param quantity: asset quantity
:param transaction_fee:
:param timestamp: transaction timestamp
:return:
"""
transaction_data = self._generate_asset_reissue_transaction(
asset_id, quantity, reissuable, transaction_fee, timestamp
)
result = self._api_client.asset_broadcast_reissue(transaction_data)
return result
[docs] @sign_required
def burn_asset(self, asset_id, quantity, transaction_fee=DEFAULT_BURN_TRANSACTION_FEE, timestamp=0):
"""
Burn asset
:param asset_id: asset id
:param quantity: asset quantity
:param transaction_fee:
:param timestamp: transaction timestamp
:return:
"""
transaction_data = self._generate_asset_burn_transaction(asset_id, quantity, transaction_fee, timestamp)
result = self._api_client.asset_broadcast_burn(transaction_data)
return result
[docs] @sign_required
def set_script(self, script, transaction_fee=DEFAULT_SET_SCRIPT_TRANSACTION_FEE, timestamp=None,
version=DEFAULT_TRANSACTION_VERSION):
"""
Set script for account
:param script:
:param transaction_fee:
:param timestamp:
:param version:
:return:
"""
transaction_data = self._generate_set_script_transaction(script, transaction_fee, timestamp, version)
result = self._api_client.transaction_broadcast(transaction_data)
return result
[docs] @sign_required
def set_asset_script(self, script, asset_id, transaction_fee=DEFAULT_SET_ASSET_SCRIPT_TRANSACTION_FEE,
timestamp=None, version=DEFAULT_TRANSACTION_VERSION):
"""
Set script for asset
:param script:
:param asset_id:
:param transaction_fee:
:param timestamp:
:param version:
:return:
"""
transaction_data = self._generate_set_asset_script_transaction(
script, asset_id, transaction_fee, timestamp, version
)
result = self._api_client.transaction_broadcast(transaction_data)
return result
def __repr__(self):
return "AcrylAddress({})".format(self.value)