def get_merkle_proof(self, tx_hash: str) -> dict: """ This interface is used to get the corresponding merkle proof based on the specified hexadecimal hash value. Args: tx_hash (str): an hexadecimal transaction hash value. Return: the merkle proof in dictionary form. """ payload = RpcClient.set_json_rpc_version(RPC_GET_MERKLE_PROOF, [tx_hash, 1]) try: response = HttpRequest.request("post", self.addr, payload) except requests.exceptions.ConnectTimeout: raise SDKException( ErrorCode.other_error(''.join(['ConnectTimeout: ', self.addr]))) except requests.exceptions.ConnectionError: raise SDKException( ErrorCode.other_error(''.join(['ConnectionError: ', self.addr]))) proof = json.loads(response.content.decode())["result"] return proof
def approve(self, owner_acct: Account, b58_spender_address: str, amount: int, payer_acct: Account, gas_limit: int, gas_price: int): """ This interface is used to call the Approve method in ope4 that allows spender to withdraw a certain amount of oep4 token from owner account multiple times. If this function is called again, it will overwrite the current allowance with new value. :param owner_acct: an Account class that indicate the owner. :param b58_spender_address: a base58 encode address that be allowed to spend the oep4 token in owner's account. :param amount: an int value that indicate the amount oep4 token that will be transferred in this transaction. :param payer_acct: an Account class that used to pay for the transaction. :param gas_limit: an int value that indicate the gas limit. :param gas_price: an int value that indicate the gas price. :return: the hexadecimal transaction hash value. """ func = self.__abi_info.get_function('approve') if not isinstance(amount, int): raise SDKException( ErrorCode.param_err('the data type of amount should be int.')) if amount < 0: raise SDKException( ErrorCode.param_err( 'the amount should be equal or great than 0.')) owner_address = owner_acct.get_address().to_array() Oep4.__b58_address_check(b58_spender_address) spender_address = Address.b58decode(b58_spender_address).to_array() params = (owner_address, spender_address, amount) func.set_params_value(params) tx_hash = self.__sdk.neo_vm().send_transaction(self.__contract_address, owner_acct, payer_acct, gas_limit, gas_price, func, False) return tx_hash
def get_smart_contract_event_by_height(self, height: int) -> dict: """ This interface is used to get the corresponding smart contract event based on the height of block. Args: height (int): a decimal height value. Return: the information of smart contract event in dictionary form. """ payload = RpcClient.set_json_rpc_version(RPC_GET_SMART_CONTRACT_EVENT, [height, 1]) try: response = HttpRequest.request("post", self.addr, payload) except requests.exceptions.ConnectTimeout: raise SDKException( ErrorCode.other_error(''.join(['ConnectTimeout: ', self.addr]))) except requests.exceptions.ConnectionError: raise SDKException( ErrorCode.other_error(''.join(['ConnectionError: ', self.addr]))) event = json.loads(response.content.decode())["result"] return event
def get_smart_contract(self, contract_address: str) -> dict: """ This interface is used to get the information of smart contract based on the specified hexadecimal hash value. :param contract_address: str, a hexadecimal hash value. :return: the information of smart contract in dictionary form. """ if type(contract_address) != str: raise SDKException( ErrorCode.param_err( 'a hexadecimal contract address is required.')) if len(contract_address) != 40: raise SDKException( ErrorCode.param_err( 'the length of the contract address should be 40 bytes.')) payload = RpcClient.set_json_rpc_version(RPC_GET_SMART_CONTRACT, [contract_address, 1]) try: response = HttpRequest.request("post", self.addr, payload) except requests.exceptions.ConnectTimeout: raise SDKException( ErrorCode.other_error(''.join(['ConnectTimeout: ', self.addr]))) except requests.exceptions.ConnectionError: raise SDKException( ErrorCode.other_error(''.join(['ConnectionError: ', self.addr]))) contract = json.loads(response.content.decode())["result"] return contract
def get_allowance(self, asset_name: str, from_address: str, to_address: str) -> str: """ This interface is used to get the the allowance from transfer-from account to transfer-to account in current network. Args: from_address (str): a base58 encoded account address Return: the information of allowance in dictionary form. """ payload = RpcClient.set_json_rpc_version( RPC_GET_ALLOWANCE, [asset_name, from_address, to_address]) try: response = HttpRequest.request("post", self.addr, payload) except requests.exceptions.ConnectTimeout: raise SDKException( ErrorCode.other_error(''.join(['ConnectTimeout: ', self.addr]))) except requests.exceptions.ConnectionError: raise SDKException( ErrorCode.other_error(''.join(['ConnectionError: ', self.addr]))) allowance = json.loads(response.content.decode())["result"] return allowance
def get_balance(self, base58_address: str) -> dict: """ This interface is used to get the account balance of specified base58 encoded address in current network. Args: base58_address (str): a base58 encoded account address Return: the value of account balance in dictionary form. """ payload = RpcClient.set_json_rpc_version(RPC_GET_BALANCE, [base58_address, 1]) try: response = HttpRequest.request("post", self.addr, payload) except requests.exceptions.ConnectTimeout: raise SDKException( ErrorCode.other_error(''.join(['ConnectTimeout: ', self.addr]))) except requests.exceptions.ConnectionError: raise SDKException( ErrorCode.other_error(''.join(['ConnectionError: ', self.addr]))) balance = json.loads(response.content.decode())["result"] return balance
def get_block_hash_by_height(self, height: int) -> str: """ This interface is used to get the hexadecimal hash value of specified block height in current network. Args: height (int): a decimal block height value Return: the hexadecimal hash value of the specified block height. """ payload = RpcClient.set_json_rpc_version(RPC_GET_BLOCK_HASH, [height, 1]) try: response = HttpRequest.request("post", self.addr, payload) except requests.exceptions.ConnectTimeout: raise SDKException( ErrorCode.other_error(''.join(['ConnectTimeout: ', self.addr]))) except requests.exceptions.ConnectionError: raise SDKException( ErrorCode.other_error(''.join(['ConnectionError: ', self.addr]))) block_hash = json.loads(response.content.decode())["result"] return block_hash
def add_multi_sign_transaction(tx: Transaction, m: int, pub_keys: list, signer: Account): """ This interface is used to generate an Transaction object which has multi signature. :param tx: a Transaction object which will be signed. :param m: the amount of signer. :param pub_keys: a list of public keys. :param signer: an Account object which will sign the transaction. :return: a Transaction object which has been signed. """ pub_keys = ProgramBuilder.sort_publickeys(pub_keys) tx_hash = tx.hash256_bytes() sig_data = signer.generate_signature(tx_hash, signer.get_signature_scheme()) if tx.sigs is None or len(tx.sigs) == 0: tx.sigs = [] elif len(tx.sigs) >= Common.TX_MAX_SIG_SIZE: raise SDKException( ErrorCode.param_err( 'the number of transaction signatures should not be over 16' )) else: for i in range(len(tx.sigs)): if tx.sigs[i].public_keys == pub_keys: if len(tx.sigs[i].sig_data) + 1 > len(pub_keys): raise SDKException( ErrorCode.param_err('too more sigData')) if tx.sigs[i].M != m: raise SDKException(ErrorCode.param_err('M error')) tx.sigs[i].sig_data.append(sig_data) return tx sig = Sig(pub_keys, m, [sig_data]) tx.sigs.append(sig) return tx
def add_multi_sign_transaction(self, tx: Transaction, m: int, pubkeys: [], signer: Account): pubkeys = ProgramBuilder.sort_publickeys(pubkeys) tx_hash = tx.hash256_bytes() sig_data = signer.generate_signature(tx_hash, signer.get_signature_scheme()) if tx.sigs is None or len(tx.sigs) == 0: tx.sigs = [] elif len(tx.sigs) >= Common.TX_MAX_SIG_SIZE: raise SDKException( ErrorCode.param_err( 'the number of transaction signatures should not be over 16' )) else: for i in range(len(tx.sigs)): if tx.sigs[i].public_keys == pubkeys: if len(tx.sigs[i].sig_data) + 1 > len(pubkeys): raise SDKException( ErrorCode.param_err('too more sigData')) if tx.sigs[i].M != m: raise SDKException(ErrorCode.param_err('M error')) tx.sigs[i].sig_data.append(sig_data) return tx sig = Sig(pubkeys, m, [sig_data]) tx.sigs.append(sig) return tx
def send_raw_transaction_pre_exec(self, tx: Transaction): """ This interface is used to send the transaction that is prepare to execute. Args: tx (Transaction): Transaction object in ontology Python SDK. Return: the execution result of transaction that is prepare to execute. """ buf = tx.serialize() tx_data = buf.hex() payload = RpcClient.set_json_rpc_version(RPC_SEND_TRANSACTION, [tx_data, 1]) try: response = HttpRequest.request("post", self.addr, payload) except requests.exceptions.ConnectTimeout: raise SDKException(ErrorCode.other_error(''.join(['ConnectTimeout: ', self.addr]))) except requests.exceptions.ConnectionError: raise SDKException(ErrorCode.other_error(''.join(['ConnectionError: ', self.addr]))) res = json.loads(response.content.decode()) err = res["error"] if err > 0: try: result = res['result'] raise RuntimeError(result) except KeyError: raise RuntimeError('send raw transaction pre-execute error') if res["result"]["State"] == 0: raise RuntimeError("State = 0") return res["result"]["Result"]
def get_block_by_hash(self, block_hash: str) -> dict: """ This interface is used to get the hexadecimal hash value of specified block height in current network. Args: block_hash (str): a hexadecimal value of block hash Return: the block information of the specified block hash. """ payload = RpcClient.set_json_rpc_version(RPC_GET_BLOCK, [block_hash, 1]) try: response = HttpRequest.request("post", self.addr, payload) except requests.exceptions.ConnectTimeout: raise SDKException( ErrorCode.other_error(''.join(['ConnectTimeout: ', self.addr]))) except requests.exceptions.ConnectionError: raise SDKException( ErrorCode.other_error(''.join(['ConnectionError: ', self.addr]))) dict_block = json.loads(response.content.decode())["result"] return dict_block
def send_raw_transaction(self, tx: Transaction) -> str: """ This interface is used to send the transaction into the network. Args: tx (Transaction): Transaction object in ontology Python SDK. Return: a hexadecimal transaction hash value. """ buf = tx.serialize() tx_data = buf.hex() payload = RpcClient.set_json_rpc_version(RPC_SEND_TRANSACTION, [tx_data]) try: response = HttpRequest.request("post", self.addr, payload) except requests.exceptions.ConnectTimeout: raise SDKException(ErrorCode.other_error(''.join(['ConnectTimeout: ', self.addr]))) except requests.exceptions.ConnectionError: raise SDKException(ErrorCode.other_error(''.join(['ConnectionError: ', self.addr]))) data = json.loads(response.content.decode()) res = data["result"] if data["error"] != 0: raise SDKException(ErrorCode.other_error(res)) return res
def get_storage(self, contract_address: str, key: str) -> int: """ This interface is used to get the corresponding stored value based on hexadecimal contract address and stored key. Args: contract_address (str): hexadecimal contract address key (str): a hexadecimal stored key Return: the information of smart contract event in dictionary form. """ payload = RpcClient.set_json_rpc_version(RPC_GET_STORAGE, [contract_address, key, 1]) try: response = HttpRequest.request("post", self.addr, payload) except requests.exceptions.ConnectTimeout: raise SDKException(ErrorCode.other_error(''.join(['ConnectTimeout: ', self.addr]))) except requests.exceptions.ConnectionError: raise SDKException(ErrorCode.other_error(''.join(['ConnectionError: ', self.addr]))) s = json.loads(response.content.decode())["result"] # s = bytearray.fromhex(s) # value = (s[0]) | (s[1]) << 8 | (s[2]) << 16 | (s[3]) << 24 | (s[4]) << 32 | (s[5]) << 40 | (s[6]) << 48 | ( # s[7]) << 56 return s
def send_transaction(self, contract_address: bytes or bytearray, acct: Account, payer_acct: Account, gas_limit: int, gas_price: int, func: AbiFunction, pre_exec: bool): if func is not None: params = BuildParams.serialize_abi_function(func) else: params = bytearray() if pre_exec: if isinstance(contract_address, bytes): tx = NeoVm.make_invoke_transaction(bytearray(contract_address), bytearray(params), b'', 0, 0) elif isinstance(contract_address, bytearray): tx = NeoVm.make_invoke_transaction(contract_address, bytearray(params), b'', 0, 0) else: raise SDKException(ErrorCode.param_err('the data type of contract address is incorrect.')) if acct is not None: self.__sdk.sign_transaction(tx, acct) return self.__sdk.rpc.send_raw_transaction_pre_exec(tx) else: unix_time_now = int(time()) params.append(0x67) for i in contract_address: params.append(i) if payer_acct is None: raise SDKException(ErrorCode.param_err('payer account is None.')) tx = Transaction(0, 0xd1, unix_time_now, gas_price, gas_limit, payer_acct.get_address().to_array(), params, bytearray(), [], bytearray()) self.__sdk.sign_transaction(tx, acct) if acct.get_address_base58() != payer_acct.get_address_base58(): self.__sdk.add_sign_transaction(tx, payer_acct) return self.__sdk.rpc.send_raw_transaction(tx)
def new_withdraw_ong_transaction(b58_claimer_address: str, b58_recv_address: str, amount: int, b58_payer_address: str, gas_limit: int, gas_price: int) -> Transaction: """ This interface is used to generate a Transaction object that allow one account to withdraw an amount of ong and transfer them to receive address. :param b58_claimer_address: a base58 encode address which is used to indicate who is the claimer. :param b58_recv_address: a base58 encode address which is used to indicate who receive the claimed ong. :param amount: the amount of asset that will be claimed. :param b58_payer_address: a base58 encode address which indicate who will pay for the transaction. :param gas_limit: an int value that indicate the gas limit. :param gas_price: an int value that indicate the gas price. :return: a Transaction object which can be used for withdraw ong. """ if not isinstance(b58_claimer_address, str) or not isinstance( b58_recv_address, str) or not isinstance( b58_payer_address, str): raise SDKException( ErrorCode.param_err( 'the data type of base58 encode address should be the string.' )) if len(b58_claimer_address) != 34 or len( b58_recv_address) != 34 or len(b58_payer_address) != 34: raise SDKException( ErrorCode.param_err( 'the length of base58 encode address should be 34 bytes.')) if amount <= 0: raise SDKException( ErrorCode.other_error( 'the amount should be greater than than zero.')) if gas_price < 0: raise SDKException( ErrorCode.other_error( 'the gas price should be equal or greater than zero.')) if gas_limit < 0: raise SDKException( ErrorCode.other_error( 'the gas limit should be equal or greater than zero.')) ont_contract_address = util.get_asset_address('onyx') ong_contract_address = util.get_asset_address("oxg") args = { "sender": Address.b58decode(b58_claimer_address).to_array(), "from": ont_contract_address, "to": Address.b58decode(b58_recv_address).to_array(), "value": amount } invoke_code = build_native_invoke_code(ong_contract_address, bytes([0]), "transferFrom", args) unix_time_now = int(time()) payer_array = Address.b58decode(b58_payer_address).to_array() return Transaction(0, 0xd1, unix_time_now, gas_price, gas_limit, payer_array, invoke_code, bytearray(), [], bytearray())
def __b58_address_check(b58_address): if not isinstance(b58_address, str): raise SDKException( ErrorCode.param_err( 'the data type of base58 encode address should be the string.' )) if len(b58_address) != 34: raise SDKException( ErrorCode.param_err( 'the length of base58 encode address should be 34 bytes.'))
def new_transfer_transaction(asset: str, b58_from_address: str, b58_to_address: str, amount: int, b58_payer_address: str, gas_limit: int, gas_price: int) -> Transaction: """ This interface is used to generate a Transaction object for transfer. :param asset: a string which is used to indicate which asset we want to transfer. :param b58_from_address: a base58 encode address which indicate where the asset from. :param b58_to_address: a base58 encode address which indicate where the asset to. :param amount: the amount of asset that will be transferred. :param b58_payer_address: a base58 encode address which indicate who will pay for the transaction. :param gas_limit: an int value that indicate the gas limit. :param gas_price: an int value that indicate the gas price. :return: a Transaction object which can be used for transfer. """ if not isinstance(b58_from_address, str) or not isinstance( b58_to_address, str) or not isinstance(b58_payer_address, str): raise SDKException( ErrorCode.param_err( 'the data type of base58 encode address should be the string.' )) if len(b58_from_address) != 34 or len(b58_to_address) != 34 or len( b58_payer_address) != 34: raise SDKException( ErrorCode.param_err( 'the length of base58 encode address should be 34 bytes.')) if amount <= 0: raise SDKException( ErrorCode.other_error( 'the amount should be greater than than zero.')) if gas_price < 0: raise SDKException( ErrorCode.other_error( 'the gas price should be equal or greater than zero.')) if gas_limit < 0: raise SDKException( ErrorCode.other_error( 'the gas limit should be equal or greater than zero.')) contract_address = util.get_asset_address(asset) raw_from = Address.b58decode(b58_from_address).to_array() raw_to = Address.b58decode(b58_to_address).to_array() raw_payer = Address.b58decode(b58_payer_address).to_array() state = [{"from": raw_from, "to": raw_to, "amount": amount}] invoke_code = build_native_invoke_code(contract_address, bytes([0]), "transfer", state) unix_time_now = int(time()) version = 0 tx_type = 0xd1 attributes = bytearray() signers = list() hash_value = bytearray() return Transaction(version, tx_type, unix_time_now, gas_price, gas_limit, raw_payer, invoke_code, attributes, signers, hash_value)
def transfer_from(self, spender_acct: Account, from_acct: Account, b58_to_address: str, value: int, payer_acct: Account, gas_limit: int, gas_price: int): """ This interface is used to call the Allowance method in ope4 that allow spender to withdraw amount of oep4 token from from-account to to-account. :param spender_acct: an Account class that spend the oep4 token. :param from_acct: an Account class that actually pay oep4 token for the spender's spending. :param b58_to_address: a base58 encode address that receive the oep4 token. :param value: the amount of ope4 token in this transaction. :param payer_acct: an Account class that used to pay for the transaction. :param gas_limit: an int value that indicate the gas limit. :param gas_price: an int value that indicate the gas price. :return: the hexadecimal transaction hash value. """ func = self.__abi_info.get_function('TransferFrom') Oep4.__b58_address_check(b58_to_address) if not isinstance(from_acct, Account): raise SDKException( ErrorCode.param_err( 'the data type of from_acct should be Account.')) if not isinstance(spender_acct, Account): raise SDKException( ErrorCode.param_err( 'the data type of spender_acct should be Account.')) spender_address_array = spender_acct.get_address().to_array() from_address_array = from_acct.get_address().to_array() to_address_array = Address.b58decode(b58_to_address).to_array() if not isinstance(value, int): raise SDKException( ErrorCode.param_err('the data type of value should be int.')) params = (spender_address_array, from_address_array, to_address_array, value) func.set_params_value(params) params = BuildParams.serialize_abi_function(func) unix_time_now = int(time.time()) params.append(0x67) for i in self.__contract_address: params.append(i) if payer_acct is None: raise SDKException(ErrorCode.param_err('payer account is None.')) payer_address_array = payer_acct.get_address().to_array() tx = Transaction(0, 0xd1, unix_time_now, gas_price, gas_limit, payer_address_array, params, bytearray(), [], bytearray()) self.__sdk.sign_transaction(tx, payer_acct) if spender_acct.get_address_base58() != payer_acct.get_address_base58( ): self.__sdk.add_sign_transaction(tx, spender_acct) if from_acct.get_address_base58() != payer_acct.get_address_base58(): self.__sdk.add_sign_transaction(tx, payer_acct) tx_hash = self.__sdk.rpc.send_raw_transaction(tx) return tx_hash
def send_transfer(self, admin_identity: Identity, password: str, key_no: int, contract_address: str, new_admin_ont_id, payer: Account, gas_limit: int, gas_price: int): if admin_identity is None or password is None or password == '' or contract_address is None or contract_address == '' or new_admin_ont_id is None or new_admin_ont_id == '' or payer is None: raise SDKException(ErrorCode.param_err("parameter should not be None")) if key_no < 0 or gas_limit < 0 or gas_price < 0: raise SDKException(ErrorCode.param_err('key_no or gas_limit or gas_price should not less than 0')) tx = self.make_transfer(contract_address, new_admin_ont_id, key_no, payer, gas_limit, gas_price) account = self.__sdk.wallet_manager.get_account(admin_identity.ont_id, password) self.__sdk.sign_transaction(tx, account) if payer is not None and account.get_address_base58() is not payer.get_address_base58(): self.__sdk.add_sign_transaction(tx, payer) self.__sdk.rpc.send_raw_transaction(tx) return tx.hash256_explorer()
def transfer_multi(self, args: list, payer_acct: Account, signers: list, gas_limit: int, gas_price: int): """ This interface is used to call the TransferMulti method in ope4 that allow transfer amount of token from multiple from-account to multiple to-account multiple times. :param args: a parameter list with each item contains three sub-items: base58 encode transaction sender address, base58 encode transaction receiver address, amount of token in transaction. :param payer_acct: an Account class that used to pay for the transaction. :param signers: a signer list used to sign this transaction which should contained all sender in args. :param gas_limit: an int value that indicate the gas limit. :param gas_price: an int value that indicate the gas price. :return: the hexadecimal transaction hash value. """ func = self.__abi_info.get_function('transferMulti') for index in range(len(args)): item = args[index] Oep4.__b58_address_check(item[0]) Oep4.__b58_address_check(item[1]) if not isinstance(item[2], float) or isinstance(item[2], int): raise SDKException( ErrorCode.param_err( 'the data type of value should be number.')) if item[2] < 0: raise SDKException( ErrorCode.param_err( 'the value should be equal or great than 0.')) from_address_array = Address.b58decode(item[0]).to_array() to_address_array = Address.b58decode(item[1]).to_array() args[index] = [ from_address_array, to_address_array, self.__to_int_according_to_decimal(item[2]) ] func.set_params_value((args, )) params = BuildParams.serialize_abi_function(func) unix_time_now = int(time.time()) params.append(0x67) for i in self.__contract_address: params.append(i) signers_len = len(signers) if signers_len == 0: raise SDKException(ErrorCode.param_err('payer account is None.')) payer_address = payer_acct.get_address().to_array() tx = Transaction(0, 0xd1, unix_time_now, gas_price, gas_limit, payer_address, params, bytearray(), [], bytearray()) for index in range(signers_len): self.__sdk.add_sign_transaction(tx, signers[index]) tx_hash = self.__sdk.rpc.send_raw_transaction(tx) return tx_hash
def send_transfer_from(self, asset: str, sender: Account, b58_from_address: str, b58_recv_address: str, amount: int, payer: Account, gas_limit: int, gas_price: int) -> str: """ This interface is used to generate a Transaction object for transfer that allow one account to transfer a amount of ONT or ONG Asset to another account, in the condition of the first account had been approved. :param asset: a string which is used to indicate which asset we want to transfer. :param sender: an Account class that send the transfer transaction. :param b58_from_address: a base58 encode address which indicate where the asset from. :param b58_recv_address: a base58 encode address which indicate where the asset to. :param amount: the amount of asset want to transfer from from-address. :param payer: an Account class that used to pay for the transaction. :param gas_limit: an int value that indicate the gas limit. :param gas_price: an int value that indicate the gas price. :return: hexadecimal transaction hash value. """ if sender is None: raise SDKException( ErrorCode.param_err('the sender should not be None.')) if payer is None: raise SDKException( ErrorCode.param_err('the payer should not be None.')) if amount <= 0: raise SDKException( ErrorCode.other_error( 'the amount should be greater than than zero.')) if gas_price < 0: raise SDKException( ErrorCode.other_error( 'the gas price should be equal or greater than zero.')) if gas_limit < 0: raise SDKException( ErrorCode.other_error( 'the gas limit should be equal or greater than zero.')) b58_payer_address = payer.get_address_base58() b58_sender_address = sender.get_address_base58() tx = Asset.new_transfer_from_transaction(asset, b58_sender_address, b58_from_address, b58_recv_address, amount, b58_payer_address, gas_limit, gas_price) tx = self.__sdk.sign_transaction(tx, sender) if b58_sender_address != b58_payer_address: tx = self.__sdk.add_sign_transaction(tx, payer) self.__sdk.rpc.send_raw_transaction(tx) return tx.hash256_explorer()
def new_approve_transaction(asset: str, b58_send_address: str, b58_recv_address: str, amount: int, b58_payer_address: str, gas_limit: int, gas_price: int) -> Transaction: """ This interface is used to generate a Transaction object for approve. :param asset: a string which is used to indicate which asset we want to approve. :param b58_send_address: a base58 encode address which indicate where the approve from. :param b58_recv_address: a base58 encode address which indicate where the approve to. :param amount: the amount of asset that will be approved. :param b58_payer_address: a base58 encode address which indicate who will pay for the transaction. :param gas_limit: an int value that indicate the gas limit. :param gas_price: an int value that indicate the gas price. :return: a Transaction object which can be used for approve. """ if not isinstance(b58_send_address, str) or not isinstance( b58_recv_address, str): raise SDKException( ErrorCode.param_err( 'the data type of base58 encode address should be the string.' )) if len(b58_send_address) != 34 or len(b58_recv_address) != 34: raise SDKException( ErrorCode.param_err( 'the length of base58 encode address should be 34 bytes.')) if amount <= 0: raise SDKException( ErrorCode.other_error( 'the amount should be greater than than zero.')) if gas_price < 0: raise SDKException( ErrorCode.other_error( 'the gas price should be equal or greater than zero.')) if gas_limit < 0: raise SDKException( ErrorCode.other_error( 'the gas limit should be equal or greater than zero.')) contract_address = util.get_asset_address(asset) raw_send = Address.b58decode(b58_send_address).to_array() raw_recv = Address.b58decode(b58_recv_address).to_array() raw_payer = Address.b58decode(b58_payer_address).to_array() args = {"from": raw_send, "to": raw_recv, "amount": amount} invoke_code = build_native_invoke_code(contract_address, bytes([0]), "approve", args) unix_time_now = int(time()) return Transaction(0, 0xd1, unix_time_now, gas_price, gas_limit, raw_payer, invoke_code, bytearray(), [], bytearray())
def set_contract_address(self, contract_address: str or bytearray or bytes): if len(contract_address) == 20: if isinstance(contract_address, bytes): self.__contract_address = bytearray(contract_address) self.__update_abi_info() elif isinstance(contract_address, bytearray): self.__contract_address = contract_address self.__update_abi_info() else: raise SDKException(ErrorCode.param_err('the data type of the contract address unsupported.')) elif isinstance(contract_address, str) and len(contract_address) == 40: self.__contract_address = binascii.a2b_hex(contract_address) self.__update_abi_info() else: raise SDKException(ErrorCode.param_err('the length of contract address should be 20 bytes.'))
def get_smart_contract(self, contract_address: str) -> dict: """ This interface is used to get the information of smart contract based on the specified hexadecimal hash value. :param contract_address: str, a hexadecimal hash value. :return: the information of smart contract in dictionary form. """ if type(contract_address) != str: raise SDKException(ErrorCode.param_err('a hexadecimal contract address is required.')) if len(contract_address) != 40: raise SDKException(ErrorCode.param_err('the length of the contract address should be 40 bytes.')) rpc_struct = RpcClient.set_json_rpc_version(RPC_GET_SMART_CONTRACT, [contract_address, 1]) r = HttpRequest.request("post", self.addr, rpc_struct) contract = json.loads(r.content.decode())["result"] return contract
def read_serializable_array(self, class_name, max=sys.maxsize): """ Deserialize a stream into the object specific by `class_name`. Args: class_name (str): a full path to the class to be deserialized into. e.g. 'neo.Core.Block.Block' max (int): (Optional) maximum number of bytes to read. Returns: list: list of `class_name` objects deserialized from the stream. """ module = '.'.join(class_name.split('.')[:-1]) klassname = class_name.split('.')[-1] klass = getattr(importlib.import_module(module), klassname) length = self.read_var_int(max=max) items = [] try: for i in range(0, length): item = klass() item.Deserialize(self) items.append(item) except Exception as e: raise SDKException(ErrorCode.param_err("Couldn't deserialize %s" % e)) return items
def read_var_int(self, max=sys.maxsize): """ Read a variable length integer from the stream. The NEO network protocol supports encoded storage for space saving. See: http://docs.neo.org/en-us/node/network-protocol.html#convention Args: max (int): (Optional) maximum number of bytes to read. Returns: int: """ fb = self.read_byte() if fb is 0: return fb value = 0 if hex(fb) == '0xfd': value = self.read_uint16() elif hex(fb) == '0xfe': value = self.read_uint32() elif hex(fb) == '0xff': value = self.read_uint64() else: value = fb if value > max: raise SDKException(ErrorCode.param_err('Invalid format')) return int(value)
def load(self): with open(self.wallet_path, "rb") as f: content = f.read() if content.startswith(codecs.BOM_UTF8): content = content[len(codecs.BOM_UTF8):] obj = json.loads(content) try: create_time = obj['createTime'] except KeyError: create_time = '' try: default_id = obj['defaultOntid'] except KeyError: default_id = '' try: default_address = obj['defaultAccountAddress'] except KeyError: default_address = '' try: identities = obj['identities'] except KeyError: identities = list() try: scrypt_dict = obj['scrypt'] scrypt_obj = Scrypt(scrypt_dict.get('n', 16384), scrypt_dict.get('r', 8), scrypt_dict.get('p', 8), scrypt_dict.get('dk_len', 64)) wallet = WalletData(obj['name'], obj['version'], create_time, default_id, default_address, scrypt_obj, identities, obj['accounts']) except KeyError as e: raise SDKException(ErrorCode.param_err('wallet file format error: %s.' % e)) return wallet
def load(self): with open(self.wallet_path, "r") as f: content = f.read() if content.startswith(u'\ufeff'): content = content.encode('utf8')[3:].decode('utf8') obj = json.loads(content) try: create_time = obj['createTime'] except KeyError: create_time = '' try: default_id = obj['defaultOntid'] except KeyError: default_id = '' try: default_address = obj['defaultAccountAddress'] except KeyError: default_address = '' try: identities = obj['identities'] except KeyError: identities = list() try: wallet = WalletData(obj['name'], obj['version'], create_time, default_id, default_address, obj['scrypt'], identities, obj['accounts']) except KeyError as e: raise SDKException(ErrorCode.param_err('wallet file format error: %s.' % e)) return wallet
def test_other_error(self): code = 59000 msg = 'TEST' desc = "Other Error, " + msg value = ErrorCode.other_error(msg) self.assertEqual(value["error"], code) self.assertEqual(value["desc"], desc)
def load(self): with open(self.wallet_path, "r") as f: obj = json.load(f) try: create_time = obj['createTime'] except KeyError: create_time = '' try: default_id = obj['defaultOntid'] except KeyError: default_id = '' try: default_address = obj['defaultAccountAddress'] except KeyError: default_address = '' try: identities = obj['identities'] except KeyError: identities = list() try: wallet = WalletData(obj['name'], obj['version'], create_time, default_id, default_address, obj['scrypt'], identities, obj['accounts']) except KeyError as e: raise SDKException(ErrorCode.param_err('wallet file format error: %s.' % e)) return wallet