def init(self, secret_hash, recipient_address, sender_address, sequence=bitcoin["sequence"]): """ Initialize Bitcoin Hash Time Lock Contract (HTLC). :param secret_hash: secret sha-256 hash. :type secret_hash: str :param recipient_address: Bitcoin recipient address. :type recipient_address: str :param sender_address: Bitcoin sender address. :type sender_address: str :param sequence: Bitcoin sequence number of expiration block, defaults to 1000. :type sequence: int :returns: HTLC -- Bitcoin Hash Time Lock Contract (HTLC) instance. >>> from swap.providers.bitcoin.htlc import HTLC >>> htlc = HTLC(network="testnet") >>> htlc.init(secret_hash="3a26da82ead15a80533a02696656b14b5dbfd84eb14790f2e1be5e9e45820eeb", recipient_address="muTnffLDR5LtFeLR2i3WsKVfdyvzfyPnVB", sender_address="mphBPZf15cRFcL5tUq6mCbE84XobZ1vg7Q", sequence=1000) <swap.providers.bitcoin.htlc.HTLC object at 0x0409DAF0> """ # Checking parameter instances if not isinstance(secret_hash, str): raise TypeError("secret hash must be string format") if len(secret_hash) != 64: raise ValueError("invalid secret hash, length must be 64.") if not isinstance(recipient_address, str): raise TypeError("recipient address must be string format") if not is_address(recipient_address, self.network): raise AddressError("invalid %s recipient %s address" % (self.network, recipient_address)) if not isinstance(sender_address, str): raise TypeError("sender address must be string format") if not is_address(sender_address, self.network): raise AddressError("invalid %s sender %s address" % (self.network, sender_address)) if not isinstance(sequence, int): raise TypeError("sequence must be integer format") # HASH TIME LOCK CONTRACT SCRIPT self.script = IfElseScript( # If branch Hashlock256Script( # Hash lock 250 hashlib.sha256(unhexlify(secret_hash)).digest( ), # Secret double hash for (OP_HASH256) script_from_address( address=recipient_address, network=self.network) # Script hash of account two ), # Else branch RelativeTimelockScript( # Relative time locked script Sequence(sequence), # Expiration blocks script_from_address( address=sender_address, network=self.network) # Script hash of account one )) return self
def init(self, secret_hash, recipient_address, sender_address, sequence=bitcoin["sequence"]): """ Initialize Bitcoin Hash Time Lock Contract (HTLC). :param secret_hash: secret sha-256 hash. :type secret_hash: hash :param recipient_address: Bitcoin recipient address. :type recipient_address: str :param sender_address: Bitcoin sender address. :type sender_address: str :param sequence: Bitcoin sequence number of expiration block, defaults to Bitcoin config sequence (15). :type sequence: int :returns: HTLC -- Bitcoin Hash Time Lock Contract (HTLC) instance. >>> from shuttle.providers.bitcoin.htlc import HTLC >>> htlc = HTLC(network="testnet") >>> htlc.init(secret_hash, recipient_address, sender_address, 100) <shuttle.providers.bitcoin.htlc.HTLC object at 0x0409DAF0> """ # Checking parameter instances if not isinstance(secret_hash, str): raise TypeError("secret hash must be string format") if len(secret_hash) != 64: raise ValueError("invalid secret hash, length must be 64.") if not isinstance(recipient_address, str): raise TypeError("recipient address must be string format") if not is_address(recipient_address, self.network): raise AddressError("invalid %s recipient %s address" % (self.network, recipient_address)) if not isinstance(sender_address, str): raise TypeError("sender address must be string format") if not is_address(sender_address, self.network): raise AddressError("invalid %s sender %s address" % (self.network, sender_address)) if not isinstance(sequence, int): raise TypeError("sequence must be integer format") # HASH TIME LOCK CONTRACT SCRIPT self.script = IfElseScript( # If branch Hashlock256Script( # Hash lock 250 sha256(unhexlify(secret_hash)), # Secret key script_from_address( address=recipient_address, network=self.network) # Script hash of account two ), # Else branch RelativeTimelockScript( # Relative time locked script Sequence(sequence), # Expiration blocks script_from_address( address=sender_address, network=self.network) # Script hash of account one )) return self
def build_htlc(self, secret_hash: str, recipient_address: str, sender_address: str, sequence: int = config["sequence"]) -> "HTLC": """ Build Bitcoin Hash Time Lock Contract (HTLC). :param secret_hash: secret sha-256 hash. :type secret_hash: str :param recipient_address: Bitcoin recipient address. :type recipient_address: str :param sender_address: Bitcoin sender address. :type sender_address: str :param sequence: Bitcoin sequence number of expiration block, defaults to 1000. :type sequence: int :returns: HTLC -- Bitcoin Hash Time Lock Contract (HTLC) instance. >>> from swap.providers.bitcoin.htlc import HTLC >>> from swap.utils import sha256 >>> htlc = HTLC(network="testnet") >>> htlc.build_htlc(secret_hash=sha256("Hello Meheret!"), recipient_address="mgokpSJoX7npmAK1Zj8ze1926CLxYDt1iF", sender_address="mkFWGt4hT11XS8dJKzzRFsTrqjjAwZfQAC", sequence=1000) <swap.providers.bitcoin.htlc.HTLC object at 0x0409DAF0> """ # Check parameter instances if len(secret_hash) != 64: raise ValueError("Invalid secret hash, length must be 64.") if not is_address(address=recipient_address, network=self._network): raise AddressError( f"Invalid Bitcoin recipient '{recipient_address}' {self._network} address." ) if not is_address(address=sender_address, network=self._network): raise AddressError( f"Invalid Bitcoin sender '{sender_address}' {self._network} address." ) self._script = IfElseScript( Hashlock256Script( hashlib.sha256(unhexlify(secret_hash)).digest(), get_address_hash(address=recipient_address, script=True)), RelativeTimelockScript( Sequence(sequence), get_address_hash(address=sender_address, script=True))) return self
class HTLC: """ Bitcoin Hash Time Lock Contract (HTLC) class. :param network: bitcoin network, defaults to testnet. :type network: str :returns: HTLC -- bitcoin HTLC instance. .. note:: Bitcoin has only two networks, ``mainnet`` and ``testnet``. """ # Initialization def __init__(self, network="testnet"): # Bitcoin network self.mainnet = None self.network = network if self.network == "mainnet": self.mainnet = True elif self.network == "testnet": self.mainnet = False else: raise ValueError("invalid network, only mainnet or testnet") # HTLC script self.script = None # Initialize new HTLC Contract script def init(self, secret_hash, recipient_address, sender_address, sequence=bitcoin["sequence"]): """ Initialize bitcoin Hash Time Lock Contract (HTLC). :param secret_hash: secret sha-256 hash. :type secret_hash: hash :param recipient_address: bitcoin recipient address. :type recipient_address: str :param sender_address: bitcoin sender address. :type sender_address: str :param sequence: bitcoin sequence number of expiration block, defaults to bitcoin config sequence (15). :type sequence: int :returns: HTLC -- bitcoin Hash Time Lock Contract (HTLC) instance. >>> from shuttle.providers.bitcoin.htlc import HTLC >>> htlc = HTLC(network="testnet") >>> htlc.init(secret_hash, recipient_address, sender_address, 100) <shuttle.providers.bitcoin.htlc.HTLC object at 0x0409DAF0> """ # Checking parameters if not isinstance(secret_hash, str): raise TypeError("secret hash must be string format") if len(secret_hash) != 64: raise ValueError("invalid secret hash, length must be 64.") if not isinstance(recipient_address, str): raise TypeError("recipient address must be string format") if not is_address(recipient_address, self.network): raise AddressError("invalid %s recipient %s address" % (self.network, recipient_address)) if not isinstance(sender_address, str): raise TypeError("sender address must be string format") if not is_address(sender_address, self.network): raise AddressError("invalid %s sender %s address" % (self.network, sender_address)) if not isinstance(sequence, int): raise TypeError("sequence must be integer format") # HASH TIME LOCK CONTRACT SCRIPT self.script = IfElseScript( # If branch Hashlock256Script( # Hash lock 250 sha256(unhexlify(secret_hash)), # Secret key script_from_address( address=recipient_address, network=self.network) # Script hash of account two ), # Else branch RelativeTimelockScript( # Relative time locked script Sequence(sequence), # Expiration blocks script_from_address( address=sender_address, network=self.network) # Script hash of account one ) ) return self # Hash time lock contract form opcode script def from_opcode(self, opcode): """ Initiate bitcoin Hash Time Lock Contract (HTLC) from opcode script. :param opcode: Bitcoin opcode script. :type opcode: str. :returns: HTLC -- bitcoin Hash Time Lock Contract (HTLC) instance. >>> from shuttle.providers.bitcoin.htlc import HTLC >>> htlc = HTLC(network="testnet") >>> htlc.from_opcode(htlc_opcode_script) <shuttle.providers.bitcoin.htlc.HTLC object at 0x0409DAF0> """ if isinstance(opcode, str): bytecode = Script.compile(opcode) self.script = ScriptBuilder.identify(bytecode) return self raise TypeError("op_code must be string format") # Hash time lock contract form bytecode def from_bytecode(self, bytecode): """ Initiate bitcoin Hash Time Lock Contract (HTLC) from bytecode. :param bytecode: Bitcoin bytecode. :type bytecode: str. :returns: HTLC -- bitcoin Hash Time Lock Contract (HTLC) instance. >>> from shuttle.providers.bitcoin.htlc import HTLC >>> htlc = HTLC(network="testnet") >>> htlc.from_bytecode(htlc_bytecode) <shuttle.providers.bitcoin.htlc.HTLC object at 0x0409DAF0> """ if isinstance(bytecode, str): self.script = ScriptBuilder.identify(bytecode) return self raise TypeError("bytecode must be string format") # Bytecode HTLC script def bytecode(self): """ Get bitcoin htlc bytecode. :returns: str -- bitcoin Hash Time Lock Contract (HTLC) bytecode. >>> from shuttle.providers.bitcoin.htlc import HTLC >>> htlc = HTLC(network="testnet") >>> htlc.init(secret_hash, recipient_address, sender_address, 100) >>> htlc.bytecode() "63aa20b9b9a0c47ecee7fd94812573a7b14afa02ec250dbdb5875a55c4d02367fcc2ab8876a9147b7c4431a43b612a72f8229935c469f1f690365888ac6755b27576a9146bce65e58a50b97989930e9a4ff1ac1a77515ef188ac68" """ if self.script is None: raise ValueError("htlc script is none, initialization htlc first") return self.script.hexlify() # Decompiled HTLC script def opcode(self): """ Get bitcoin htlc opcode. :returns: str -- bitcoin Hash Time Lock Contract (HTLC) opcode. >>> from shuttle.providers.bitcoin.htlc import HTLC >>> htlc = HTLC(network="testnet") >>> htlc.init(secret_hash, recipient_address, sender_address, 100) >>> htlc.opcode() "OP_IF OP_HASH256 b9b9a0c47ecee7fd94812573a7b14afa02ec250dbdb5875a55c4d02367fcc2ab OP_EQUALVERIFY OP_DUP OP_HASH160 7b7c4431a43b612a72f8229935c469f1f6903658 OP_EQUALVERIFY OP_CHECKSIG OP_ELSE OP_5 OP_CHECKSEQUENCEVERIFY OP_DROP OP_DUP OP_HASH160 6bce65e58a50b97989930e9a4ff1ac1a77515ef1 OP_EQUALVERIFY OP_CHECKSIG OP_ENDIF" """ if self.script is None: raise ValueError("htlc script is none, initialization htlc first") return self.script.decompile() # HTLC script hash def hash(self): """ Get bitcoin Hash Time Lock Contract (HTLC) hash. :returns: str -- bitcoin Hash Time Lock Contract (HTLC) hash. >>> from shuttle.providers.bitcoin.htlc import HTLC >>> htlc = HTLC(network="testnet") >>> htlc.init(secret_hash, recipient_address, sender_address, 100) >>> htlc.hash() "a914971894c58d85981c16c2059d422bcde0b156d04487" """ if self.script is None: raise ValueError("htlc script is none, initialization htlc first") return P2shScript(self.script.p2sh_hash()).hexlify() # HTLC script address def address(self): """ Get bitcoin Hash Time Lock Contract (HTLC) address. :returns: str -- bitcoin Hash Time Lock Contract (HTLC) address. >>> from shuttle.providers.bitcoin.htlc import HTLC >>> htlc = HTLC(network="testnet") >>> htlc.init(secret_hash, recipient_address, sender_address, 100) >>> htlc.address() "2N729UBGZB3xjsGFRgKivy4bSjkaJGMVSpB" """ if self.script is None: raise ValueError("htlc script is none, initialization htlc first") return P2shScript(self.script.p2sh_hash()).address(mainnet=self.mainnet)
class HTLC: """ Bitcoin Hash Time Lock Contract (HTLC). :param network: Bitcoin network, defaults to mainnet. :type network: str :returns: HTLC -- Bitcoin HTLC instance. .. note:: Bitcoin has only two networks, ``mainnet`` and ``testnet``. """ def __init__(self, network: str = config["network"]): if not is_network(network=network): raise NetworkError(f"Invalid Bitcoin '{network}' network", "choose only 'mainnet' or 'testnet' networks.") self._network: str = network self._script: Optional[IfElseScript, ScriptBuilder] = None @property def script(self) -> Union[IfElseScript, ScriptBuilder]: return self._script def build_htlc(self, secret_hash: str, recipient_address: str, sender_address: str, sequence: int = config["sequence"]) -> "HTLC": """ Build Bitcoin Hash Time Lock Contract (HTLC). :param secret_hash: secret sha-256 hash. :type secret_hash: str :param recipient_address: Bitcoin recipient address. :type recipient_address: str :param sender_address: Bitcoin sender address. :type sender_address: str :param sequence: Bitcoin sequence number of expiration block, defaults to 1000. :type sequence: int :returns: HTLC -- Bitcoin Hash Time Lock Contract (HTLC) instance. >>> from swap.providers.bitcoin.htlc import HTLC >>> from swap.utils import sha256 >>> htlc = HTLC(network="testnet") >>> htlc.build_htlc(secret_hash=sha256("Hello Meheret!"), recipient_address="mgokpSJoX7npmAK1Zj8ze1926CLxYDt1iF", sender_address="mkFWGt4hT11XS8dJKzzRFsTrqjjAwZfQAC", sequence=1000) <swap.providers.bitcoin.htlc.HTLC object at 0x0409DAF0> """ # Check parameter instances if len(secret_hash) != 64: raise ValueError("Invalid secret hash, length must be 64.") if not is_address(address=recipient_address, network=self._network): raise AddressError( f"Invalid Bitcoin recipient '{recipient_address}' {self._network} address." ) if not is_address(address=sender_address, network=self._network): raise AddressError( f"Invalid Bitcoin sender '{sender_address}' {self._network} address." ) self._script = IfElseScript( Hashlock256Script( hashlib.sha256(unhexlify(secret_hash)).digest(), get_address_hash(address=recipient_address, script=True)), RelativeTimelockScript( Sequence(sequence), get_address_hash(address=sender_address, script=True))) return self def from_opcode(self, opcode: str) -> "HTLC": """ Initiate Bitcoin Hash Time Lock Contract (HTLC) from opcode script. :param opcode: Bitcoin opcode script. :type opcode: str :returns: HTLC -- Bitcoin Hash Time Lock Contract (HTLC) instance. >>> from swap.providers.bitcoin.htlc import HTLC >>> htlc = HTLC(network="testnet") >>> opcode = "OP_IF OP_HASH256 821124b554d13f247b1e5d10b84e44fb1296f18f38bbaa1bea34a12c843e0158 OP_EQUALVERIFY OP_DUP OP_HASH160 0e259e08f2ec9fc99a92b6f66fdfcb3c7914fd68 OP_EQUALVERIFY OP_CHECKSIG OP_ELSE e803 OP_CHECKSEQUENCEVERIFY OP_DROP OP_DUP OP_HASH160 33ecab3d67f0e2bde43e52f41ec1ecbdc73f11f8 OP_EQUALVERIFY OP_CHECKSIG OP_ENDIF" >>> htlc.from_opcode(opcode=opcode) <swap.providers.bitcoin.htlc.HTLC object at 0x0409DAF0> """ bytecode = Script.compile(opcode) self._script = ScriptBuilder.identify(bytecode) return self def from_bytecode(self, bytecode: str) -> "HTLC": """ Initialize Bitcoin Hash Time Lock Contract (HTLC) from bytecode. :param bytecode: Bitcoin bytecode. :type bytecode: str :returns: HTLC -- Bitcoin Hash Time Lock Contract (HTLC) instance. >>> from swap.providers.bitcoin.htlc import HTLC >>> htlc = HTLC(network="testnet") >>> bytecode = "63aa20821124b554d13f247b1e5d10b84e44fb1296f18f38bbaa1bea34a12c843e01588876a9140e259e08f2ec9fc99a92b6f66fdfcb3c7914fd6888ac6702e803b27576a91433ecab3d67f0e2bde43e52f41ec1ecbdc73f11f888ac68" >>> htlc.from_bytecode(bytecode=bytecode) <swap.providers.bitcoin.htlc.HTLC object at 0x0409DAF0> """ self._script = ScriptBuilder.identify(bytecode) return self def bytecode(self) -> str: """ Get Bitcoin Hash Time Lock Contract (HTLC) bytecode. :returns: str -- Bitcoin HTLC bytecode. >>> from swap.providers.bitcoin.htlc import HTLC >>> from swap.utils import sha256 >>> htlc = HTLC(network="testnet") >>> htlc.build_htlc(sha256("Hello Meheret!"), "mgokpSJoX7npmAK1Zj8ze1926CLxYDt1iF", "mkFWGt4hT11XS8dJKzzRFsTrqjjAwZfQAC", 1000) >>> htlc.bytecode() "63aa20821124b554d13f247b1e5d10b84e44fb1296f18f38bbaa1bea34a12c843e01588876a9140e259e08f2ec9fc99a92b6f66fdfcb3c7914fd6888ac6702e803b27576a91433ecab3d67f0e2bde43e52f41ec1ecbdc73f11f888ac68" """ if self._script is None: raise ValueError("HTLC script is None, first build HTLC.") return self._script.hexlify() def opcode(self) -> str: """ Get Bitcoin Hash Time Lock Contract (HTLC) OP_Code. :returns: str -- Bitcoin HTLC opcode. >>> from swap.providers.bitcoin.htlc import HTLC >>> from swap.utils import sha256 >>> htlc = HTLC(network="testnet") >>> htlc.build_htlc(sha256("Hello Meheret!"), "mgokpSJoX7npmAK1Zj8ze1926CLxYDt1iF", "mkFWGt4hT11XS8dJKzzRFsTrqjjAwZfQAC", 1000) >>> htlc.opcode() "OP_IF OP_HASH256 821124b554d13f247b1e5d10b84e44fb1296f18f38bbaa1bea34a12c843e0158 OP_EQUALVERIFY OP_DUP OP_HASH160 0e259e08f2ec9fc99a92b6f66fdfcb3c7914fd68 OP_EQUALVERIFY OP_CHECKSIG OP_ELSE e803 OP_CHECKSEQUENCEVERIFY OP_DROP OP_DUP OP_HASH160 33ecab3d67f0e2bde43e52f41ec1ecbdc73f11f8 OP_EQUALVERIFY OP_CHECKSIG OP_ENDIF" """ if self._script is None: raise ValueError("HTLC script is None, first build HTLC.") return self._script.decompile() def hash(self) -> str: """ Get Bitcoin HTLC hash. :returns: str -- Bitcoin Hash Time Lock Contract (HTLC) hash. >>> from swap.providers.bitcoin.htlc import HTLC >>> from swap.utils import sha256 >>> htlc = HTLC(network="testnet") >>> htlc.build_htlc(sha256("Hello Meheret!"), "mgokpSJoX7npmAK1Zj8ze1926CLxYDt1iF", "mkFWGt4hT11XS8dJKzzRFsTrqjjAwZfQAC", 1000) >>> htlc.hash() "a9149418feed4647e156d6663db3e0cef7c050d0386787" """ if self._script is None: raise ValueError("HTLC script is None, first build HTLC.") return str(P2shScript(self._script.p2sh_hash()).hexlify()) def address(self) -> str: """ Get Bitcoin Hash Time Lock Contract (HTLC) address. :returns: str -- Bitcoin HTLC address. >>> from swap.providers.bitcoin.htlc import HTLC >>> from swap.utils import sha256 >>> htlc = HTLC(network="testnet") >>> htlc.build_htlc(sha256("Hello Meheret!"), "mgokpSJoX7npmAK1Zj8ze1926CLxYDt1iF", "mkFWGt4hT11XS8dJKzzRFsTrqjjAwZfQAC", 1000) >>> htlc.address() "2N6kHwQy6Ph5EdKNgzGrcW2WhGHKGfmP5ae" """ if self._script is None: raise ValueError("HTLC script is None, first build HTLC.") return str( P2shScript(self._script.p2sh_hash()).address( mainnet=(True if self._network == "mainnet" else False))) def balance(self, unit: str = config["unit"]) -> Union[int, float]: """ Get Bitcoin HTLC balance. :param unit: Bitcoin unit, default to SATOSHI. :type unit: str :return: int, float -- Bitcoin wallet balance. >>> from swap.providers.bitcoin.htlc import HTLC >>> from swap.utils import sha256 >>> htlc = HTLC(network="testnet") >>> htlc.build_htlc(sha256("Hello Meheret!"), "mgokpSJoX7npmAK1Zj8ze1926CLxYDt1iF", "mkFWGt4hT11XS8dJKzzRFsTrqjjAwZfQAC", 1000) >>> htlc.balance(unit="unit") 1000010 """ if unit not in ["BTC", "mBTC", "SATOSHI"]: raise UnitError( "Invalid Bitcoin unit, choose only BTC, mBTC or SATOSHI units." ) _balance: int = get_balance(address=self.address(), network=self._network) return _balance if unit == "SATOSHI" else \ amount_unit_converter(amount=_balance, unit_from=f"SATOSHI2{unit}") def utxos(self, limit: int = 15) -> list: """ Get Bitcoin HTLC unspent transaction output (UTXO's). :param limit: Limit of UTXO's, default is 15. :type limit: int :return: list -- Bitcoin unspent transaction outputs. >>> from swap.providers.bitcoin.htlc import HTLC >>> from swap.utils import sha256 >>> htlc = HTLC(network="testnet") >>> htlc.build_htlc(sha256("Hello Meheret!"), "mgokpSJoX7npmAK1Zj8ze1926CLxYDt1iF", "mkFWGt4hT11XS8dJKzzRFsTrqjjAwZfQAC", 1000) >>> htlc.utxos() [{'index': 0, 'hash': '9825b68e57c8a924285828dde37869c2eca3bb3784b171353962f0d7e7577da1', 'output_index': 0, 'amount': 10000, 'script': 'a9149418feed4647e156d6663db3e0cef7c050d0386787'}] """ utxos = list() _utxos = get_utxos(address=self.address(), network=self._network, limit=limit) for index, utxo in enumerate(_utxos): utxos.append( dict(index=index, hash=utxo["tx_hash"], output_index=utxo["tx_output_n"], amount=utxo["value"], script=utxo["script"])) return utxos
class HTLC: """ Bitcoin Hash Time Lock Contract (HTLC) class. :param network: Bitcoin network, defaults to testnet. :type network: str :returns: HTLC -- Bitcoin HTLC instance. .. note:: Bitcoin has only two networks, ``mainnet`` and ``testnet``. """ # Initialization def __init__(self, network="testnet"): # Bitcoin network self.mainnet = None self.network = network if self.network == "mainnet": self.mainnet = True elif self.network == "testnet": self.mainnet = False else: raise ValueError("invalid network, only mainnet or testnet") # HTLC script self.script = None # Initialize new HTLC Contract script def init(self, secret_hash, recipient_address, sender_address, sequence=bitcoin["sequence"]): """ Initialize Bitcoin Hash Time Lock Contract (HTLC). :param secret_hash: secret sha-256 hash. :type secret_hash: str :param recipient_address: Bitcoin recipient address. :type recipient_address: str :param sender_address: Bitcoin sender address. :type sender_address: str :param sequence: Bitcoin sequence number of expiration block, defaults to 1000. :type sequence: int :returns: HTLC -- Bitcoin Hash Time Lock Contract (HTLC) instance. >>> from swap.providers.bitcoin.htlc import HTLC >>> htlc = HTLC(network="testnet") >>> htlc.init(secret_hash="3a26da82ead15a80533a02696656b14b5dbfd84eb14790f2e1be5e9e45820eeb", recipient_address="muTnffLDR5LtFeLR2i3WsKVfdyvzfyPnVB", sender_address="mphBPZf15cRFcL5tUq6mCbE84XobZ1vg7Q", sequence=1000) <swap.providers.bitcoin.htlc.HTLC object at 0x0409DAF0> """ # Checking parameter instances if not isinstance(secret_hash, str): raise TypeError("secret hash must be string format") if len(secret_hash) != 64: raise ValueError("invalid secret hash, length must be 64.") if not isinstance(recipient_address, str): raise TypeError("recipient address must be string format") if not is_address(recipient_address, self.network): raise AddressError("invalid %s recipient %s address" % (self.network, recipient_address)) if not isinstance(sender_address, str): raise TypeError("sender address must be string format") if not is_address(sender_address, self.network): raise AddressError("invalid %s sender %s address" % (self.network, sender_address)) if not isinstance(sequence, int): raise TypeError("sequence must be integer format") # HASH TIME LOCK CONTRACT SCRIPT self.script = IfElseScript( # If branch Hashlock256Script( # Hash lock 250 hashlib.sha256(unhexlify(secret_hash)).digest( ), # Secret double hash for (OP_HASH256) script_from_address( address=recipient_address, network=self.network) # Script hash of account two ), # Else branch RelativeTimelockScript( # Relative time locked script Sequence(sequence), # Expiration blocks script_from_address( address=sender_address, network=self.network) # Script hash of account one )) return self # Hash time lock contract form opcode script def from_opcode(self, opcode): """ Initiate Bitcoin Hash Time Lock Contract (HTLC) from opcode script. :param opcode: Bitcoin opcode script. :type opcode: str :returns: HTLC -- Bitcoin Hash Time Lock Contract (HTLC) instance. >>> from swap.providers.bitcoin.htlc import HTLC >>> htlc = HTLC(network="testnet") >>> htlc_opcode_script = "OP_IF OP_HASH256 821124b554d13f247b1e5d10b84e44fb1296f18f38bbaa1bea34a12c843e0158 OP_EQUALVERIFY OP_DUP OP_HASH160 98f879fb7f8b4951dee9bc8a0327b792fbe332b8 OP_EQUALVERIFY OP_CHECKSIG OP_ELSE e803 OP_CHECKSEQUENCEVERIFY OP_DROP OP_DUP OP_HASH160 64a8390b0b1685fcbf2d4b457118dc8da92d5534 OP_EQUALVERIFY OP_CHECKSIG OP_ENDIF" >>> htlc.from_opcode(opcode=htlc_opcode_script) <swap.providers.bitcoin.htlc.HTLC object at 0x0409DAF0> """ if isinstance(opcode, str): bytecode = Script.compile(opcode) self.script = ScriptBuilder.identify(bytecode) return self raise TypeError("op_code must be string format") # Hash time lock contract form bytecode def from_bytecode(self, bytecode): """ Initiate Bitcoin Hash Time Lock Contract (HTLC) from bytecode. :param bytecode: Bitcoin bytecode. :type bytecode: str :returns: HTLC -- Bitcoin Hash Time Lock Contract (HTLC) instance. >>> from swap.providers.bitcoin.htlc import HTLC >>> htlc = HTLC(network="testnet") >>> htlc_bytecode = "63aa20821124b554d13f247b1e5d10b84e44fb1296f18f38bbaa1bea34a12c843e01588876a91498f879fb7f8b4951dee9bc8a0327b792fbe332b888ac6702e803b27576a91464a8390b0b1685fcbf2d4b457118dc8da92d553488ac68" >>> htlc.from_bytecode(bytecode=htlc_bytecode) <swap.providers.bitcoin.htlc.HTLC object at 0x0409DAF0> """ if isinstance(bytecode, str): self.script = ScriptBuilder.identify(bytecode) return self raise TypeError("bytecode must be string format") # Bytecode HTLC script def bytecode(self): """ Get Bitcoin htlc bytecode. :returns: str -- Bitcoin Hash Time Lock Contract (HTLC) bytecode. >>> from swap.providers.bitcoin.htlc import HTLC >>> htlc = HTLC(network="testnet") >>> htlc.init("3a26da82ead15a80533a02696656b14b5dbfd84eb14790f2e1be5e9e45820eeb", "muTnffLDR5LtFeLR2i3WsKVfdyvzfyPnVB", "mphBPZf15cRFcL5tUq6mCbE84XobZ1vg7Q", 1000) >>> htlc.bytecode() "63aa20821124b554d13f247b1e5d10b84e44fb1296f18f38bbaa1bea34a12c843e01588876a91498f879fb7f8b4951dee9bc8a0327b792fbe332b888ac6702e803b27576a91464a8390b0b1685fcbf2d4b457118dc8da92d553488ac68" """ if self.script is None: raise ValueError("htlc script is none, initialization htlc first") return self.script.hexlify() # Decompiled HTLC script def opcode(self): """ Get Bitcoin htlc opcode. :returns: str -- Bitcoin Hash Time Lock Contract (HTLC) opcode. >>> from swap.providers.bitcoin.htlc import HTLC >>> htlc = HTLC(network="testnet") >>> htlc.init("3a26da82ead15a80533a02696656b14b5dbfd84eb14790f2e1be5e9e45820eeb", "muTnffLDR5LtFeLR2i3WsKVfdyvzfyPnVB", "mphBPZf15cRFcL5tUq6mCbE84XobZ1vg7Q", 1000) >>> htlc.opcode() "OP_IF OP_HASH256 821124b554d13f247b1e5d10b84e44fb1296f18f38bbaa1bea34a12c843e0158 OP_EQUALVERIFY OP_DUP OP_HASH160 98f879fb7f8b4951dee9bc8a0327b792fbe332b8 OP_EQUALVERIFY OP_CHECKSIG OP_ELSE e803 OP_CHECKSEQUENCEVERIFY OP_DROP OP_DUP OP_HASH160 64a8390b0b1685fcbf2d4b457118dc8da92d5534 OP_EQUALVERIFY OP_CHECKSIG OP_ENDIF" """ if self.script is None: raise ValueError("htlc script is none, initialization htlc first") return self.script.decompile() # HTLC script hash def hash(self): """ Get Bitcoin Hash Time Lock Contract (HTLC) hash. :returns: str -- Bitcoin Hash Time Lock Contract (HTLC) hash. >>> from swap.providers.bitcoin.htlc import HTLC >>> htlc = HTLC(network="testnet") >>> htlc.init("3a26da82ead15a80533a02696656b14b5dbfd84eb14790f2e1be5e9e45820eeb", "muTnffLDR5LtFeLR2i3WsKVfdyvzfyPnVB", "mphBPZf15cRFcL5tUq6mCbE84XobZ1vg7Q", 1000) >>> htlc.hash() "a9142bb013c3e4beb08421dedcf815cb65a5c388178b87" """ if self.script is None: raise ValueError("htlc script is none, initialization htlc first") return str(P2shScript(self.script.p2sh_hash()).hexlify()) # HTLC script address def address(self): """ Get Bitcoin Hash Time Lock Contract (HTLC) address. :returns: str -- Bitcoin Hash Time Lock Contract (HTLC) address. >>> from swap.providers.bitcoin.htlc import HTLC >>> htlc = HTLC(network="testnet") >>> htlc.init("3a26da82ead15a80533a02696656b14b5dbfd84eb14790f2e1be5e9e45820eeb", "muTnffLDR5LtFeLR2i3WsKVfdyvzfyPnVB", "mphBPZf15cRFcL5tUq6mCbE84XobZ1vg7Q", 1000) >>> htlc.address() "2MwEDybGC34949zgzWX4M9FHmE3crDSUydP" """ if self.script is None: raise ValueError("htlc script is none, initialization htlc first") return str( P2shScript(self.script.p2sh_hash()).address(mainnet=self.mainnet))