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 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 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 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 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 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 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 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 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 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 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
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 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 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 send_approve(self, asset, sender: Account, b58_recv_address: str, amount: int, payer: Account, gas_limit: int, gas_price: int) -> str: """ This is an interface used to send an approve transaction which allow receiver to spend a amount of ONT or ONG asset in sender's account. :param asset: a string which is used to indicate what asset we want to approve. :param sender: an Account class that send the approve transaction. :param b58_recv_address: a base58 encode address which indicate where the approve to. :param amount: the amount of asset want to approve. :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_sender_address = sender.get_address_base58() b58_payer_address = payer.get_address_base58() tx = Asset.new_approve_transaction(asset, b58_sender_address, b58_recv_address, amount, b58_payer_address, gas_limit, gas_price) tx = self.__sdk.sign_transaction(tx, sender) if sender.get_address_base58() != payer.get_address_base58(): tx = self.__sdk.add_sign_transaction(tx, payer) self.__sdk.rpc.send_raw_transaction(tx) return tx.hash256_explorer()
def write_byte(self, value): if isinstance(value, bytearray) or isinstance(value, bytes): self.ms.write(value) elif isinstance(value, str): self.ms.write(value.encode()) elif isinstance(value, int): self.ms.write(bytes([value])) else: raise SDKException(ErrorCode.param_err('type error, write byte failed.'))
def send_withdraw_ong_transaction(self, claimer: Account, b58_recv_address: str, amount: int, payer: Account, gas_limit: int, gas_price: int) -> str: """ This interface is used to withdraw a amount of ong and transfer them to receive address. :param claimer: the owner of ong that remained to claim. :param b58_recv_address: the address that received the ong. :param amount: the amount of ong want to claim. :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 claimer is None: raise SDKException( ErrorCode.param_err('the claimer 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_claimer = claimer.get_address_base58() b58_payer = payer.get_address_base58() tx = Asset.new_withdraw_ong_transaction(b58_claimer, b58_recv_address, amount, b58_payer, gas_limit, gas_price) tx = self.__sdk.sign_transaction(tx, claimer) if claimer.get_address_base58() != payer.get_address_base58(): tx = self.__sdk.add_sign_transaction(tx, payer) self.__sdk.rpc.send_raw_transaction(tx) return tx.hash256_explorer()
def get_parameter(self, param_name: str) -> Parameter: """ This interface is used to get a Parameter object from an AbiFunction object which contain given function parameter's name, type and value. :param param_name: a string used to indicate which parameter we want to get from AbiFunction. :return: a Parameter object which contain given function parameter's name, type and value. """ for p in self.parameters: if p.name == param_name: return p raise SDKException(ErrorCode.param_err('get parameter failed.'))
def write_var_int(self, value, little_endian=True): """ Write an integer value in a space saving way to the stream. Args: value (int): little_endian (bool): specify the endianness. (Default) Little endian. Raises: SDKException: if `value` is not of type int. SDKException: if `value` is < 0. Returns: int: the number of bytes written. """ if little_endian: endian = "<" else: endian = ">" if not isinstance(value, int): raise SDKException(ErrorCode.param_err('%s not int type.' % value)) if value < 0: raise SDKException(ErrorCode.param_err('%d too small.' % value)) elif value < 0xfd: return self.write_byte(value) elif value <= 0xffff: self.write_byte(0xfd) return self.write_uint16(value, little_endian) elif value <= 0xFFFFFFFF: self.write_byte(0xfe) return self.write_uint32(value, little_endian) else: self.write_byte(0xff) return self.write_uint64(value, little_endian)
def transfer(self, from_acct: Account, b58_to_address: str, value: int, payer_acct: Account, gas_limit: int, gas_price: int) -> str: """ This interface is used to call the Transfer method in ope4 that transfer an amount of tokens from one account to another account. :param from_acct: an Account class that send the oep4 token. :param b58_to_address: a base58 encode address that receive the oep4 token. :param value: 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('transfer') if not isinstance(value, int) or isinstance(value, float): raise SDKException( ErrorCode.param_err( 'the data type of value should be number.')) if value < 0: raise SDKException( ErrorCode.param_err( 'the value should be equal or great than 0.')) if not isinstance(from_acct, Account): raise SDKException( ErrorCode.param_err( 'the data type of from_acct should be Account.')) Oep4.__b58_address_check(b58_to_address) from_address = from_acct.get_address().to_array() to_address = Address.b58decode(b58_to_address).to_array() value = self.__to_int_according_to_decimal(value) params = (from_address, to_address, value) func.set_params_value(params) tx_hash = self.__sdk.neo_vm().send_transaction(self.__contract_address, from_acct, payer_acct, gas_limit, gas_price, func, False) return tx_hash
def read_byte(self, do_ord=True): """ Read a single byte. Args: do_ord (bool): (default True) convert the byte to an ordinal first. Returns: bytes: a single byte if successful. 0 (int) if an exception occurred. """ try: if do_ord: return ord(self.stream.read(1)) return self.stream.read(1) except Exception as e: raise SDKException(ErrorCode.param_err(e.args[0]))
def add_sign_transaction(self, tx: Transaction, signer: Account): 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' )) tx_hash = tx.hash256_bytes() sig_data = signer.generate_signature(tx_hash, signer.get_signature_scheme()) sig = Sig([signer.serialize_public_key()], 1, [sig_data]) tx.sigs.append(sig) return tx
def send_transfer_from(self, asset: str, sender: Account, from_address: str, recv_address: str, amount: int, payer: Account, gas_limit: int, gas_price: int) -> str: if sender is None or payer is None: raise SDKException(ErrorCode.param_err('parameters should not be null')) if amount <= 0 or gas_price < 0 or gas_limit < 0: raise SDKException(ErrorCode.param_error) b58_payer = payer.get_address_base58() b58_sender = sender.get_address_base58() tx = Asset.new_transfer_from(asset, b58_sender, from_address, recv_address, amount, b58_payer, gas_limit, gas_price) tx = self.__sdk.sign_transaction(tx, sender) if b58_sender != b58_payer: tx = self.__sdk.add_sign_transaction(tx, payer) self.__sdk.rpc.send_raw_transaction(tx) return tx.hash256_explorer()
def write_fixed_str(self, value, length): """ Write a string value to the stream. Args: value (str): value to write to the stream. length (int): length of the string to write. """ towrite = value.encode('utf-8') slen = len(towrite) if slen > length: raise SDKException( ErrorCode.param_err('string longer than fixed length: %s' % length)) self.write_bytes(towrite) diff = length - slen while diff > 0: self.write_byte(0) diff -= 1