示例#1
0
    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
示例#2
0
    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
示例#3
0
    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
示例#4
0
文件: htlc.py 项目: xeroc/shuttle
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)
示例#5
0
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
示例#6
0
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))