diff --git a/docs/adapters.rst b/docs/adapters.rst
new file mode 100644
index 00000000..7551d729
--- /dev/null
+++ b/docs/adapters.rst
@@ -0,0 +1,221 @@
+Adapters and Wrappers
+=====================
+
+The ``Iota`` class defines the API methods that are available for
+interacting with the node, but it delegates the actual interaction to
+another set of classes: Adapters and Wrappers.
+
+AdapterSpec
+-----------
+
+In a few places in the PyOTA codebase, you may see references to a
+meta-type called ``AdapterSpec``.
+
+``AdapterSpec`` is a placeholder that means "URI or adapter instance".
+
+For example, the first argument of ``Iota.__init__`` is an
+``AdapterSpec``. This means that you can initialize an ``Iota`` object
+using either a node URI, or an adapter instance:
+
+- Node URI: ``Iota('http://localhost:14265')``
+- Adapter instance: ``Iota(HttpAdapter('http://localhost:14265'))``
+
+Adapters
+--------
+
+Adapters are responsible for sending requests to the node and returning
+the response.
+
+PyOTA ships with a few adapters:
+
+HttpAdapter
+~~~~~~~~~~~
+
+.. code:: python
+
+ from iota import Iota
+ from iota.adapter import HttpAdapter
+
+ # Use HTTP:
+ api = Iota('http://localhost:14265')
+ api = Iota(HttpAdapter('http://localhost:14265'))
+
+ # Use HTTPS:
+ api = Iota('https://service.iotasupport.com:14265')
+ api = Iota(HttpAdapter('https://service.iotasupport.com:14265'))
+
+``HttpAdapter`` uses the HTTP protocol to send requests to the node.
+
+To configure an ``Iota`` instance to use ``HttpAdapter``, specify an
+``http://`` or ``https://`` URI, or provide an ``HttpAdapter`` instance.
+
+The ``HttpAdapter`` raises a ``BadApiResponse`` exception if the server
+sends back an error response (due to invalid request parameters, for
+example).
+
+Debugging HTTP Requests
+^^^^^^^^^^^^^^^^^^^^^^^
+
+.. code:: python
+
+ from logging import getLogger
+
+ from iota import Iota
+
+ api = Iota('http://localhost:14265')
+ api.adapter.set_logger(getLogger(__name__))
+
+To see all HTTP requests and responses as they happen, attach a
+``logging.Logger`` instance to the adapter via its ``set_logger``
+method.
+
+Any time the ``HttpAdapter`` sends a request or receives a response, it
+will first generate a log message. Note: if the response is an error
+response (e.g., due to invalid request parameters), the ``HttpAdapter``
+will log the request before raising ``BadApiResponse``.
+
+.. note::
+
+ ``HttpAdapter`` generates log messages with ``DEBUG`` level, so make sure that your logger's ``level`` attribute is set low enough that it doesn't filter these messages!
+
+SandboxAdapter
+~~~~~~~~~~~~~~
+
+.. code:: python
+
+ from iota import Iota
+ from iota.adapter.sandbox import SandboxAdapter
+
+ api =\
+ Iota(
+ SandboxAdapter(
+ uri = 'https://sandbox.iotatoken.com/api/v1/',
+ auth_token = 'demo7982-be4a-4afa-830e-7859929d892c',
+ ),
+ )
+
+The ``SandboxAdapter`` is a specialized ``HttpAdapter`` that sends
+authenticated requests to sandbox nodes.
+
+.. note::
+
+ See `Sandbox `_ Documentation for more information about sandbox nodes.
+
+Sandbox nodes process certain commands asynchronously. When
+``SandboxAdapter`` determines that a request is processed
+asynchronously, it will block, then poll the node periodically until it
+receives a response.
+
+The result is that ``SandboxAdapter`` abstracts away the sandbox node's
+asynchronous functionality so that your API client behaves exactly the
+same as if it were connecting to a non-sandbox node.
+
+To create a ``SandboxAdapter``, you must provide the URI of the sandbox
+node and the auth token that you received from the node maintainer. Note
+that ``SandboxAdapter`` only works with ``http://`` and ``https://``
+URIs.
+
+You may also specify the polling interval (defaults to 15 seconds) and
+the number of polls before giving up on an asynchronous job (defaults to
+8 times).
+
+.. note::
+
+ For parity with the other adapters, ``SandboxAdapter`` blocks until it receives a response from the node.
+
+ If you do not want ``SandboxAdapter`` to block the main thread, it is recommended that you execute it in a separate thread or process.
+
+
+MockAdapter
+~~~~~~~~~~~
+
+.. code:: python
+
+ from iota import Iota
+ from iota.adapter import MockAdapter
+
+ # Inject a mock adapter.
+ api = Iota('mock://')
+ api = Iota(MockAdapter())
+
+ # Seed responses from the node.
+ api.adapter.seed_response('getNodeInfo', {'message': 'Hello, world!'})
+ api.adapter.seed_response('getNodeInfo', {'message': 'Hello, IOTA!'})
+
+ # Invoke API commands, using the adapter.
+ print(api.get_node_info()) # {'message': 'Hello, world!'}
+ print(api.get_node_info()) # {'message': 'Hello, IOTA!'}
+ print(api.get_node_info()) # raises BadApiResponse exception
+
+``MockAdapter`` is used to simulate the behavior of an adapter without
+actually sending any requests to the node.
+
+This is particularly useful in unit and functional tests where you want
+to verify that your code works correctly in specific scenarios, without
+having to engineer your own subtangle.
+
+To configure an ``Iota`` instance to use ``MockAdapter``, specify
+``mock://`` as the node URI, or provide a ``MockAdapter`` instance.
+
+To use ``MockAdapter``, you must first seed the responses that you want
+it to return by calling its ``seed_response`` method.
+
+``seed_response`` takes two parameters:
+
+- ``command: Text``: The name of the command. Note that this is the
+ camelCase version of the command name (e.g., ``getNodeInfo``, not
+ ``get_node_info``).
+- ``response: dict``: The response that the adapter will return.
+
+You can seed multiple responses for the same command; the
+``MockAdapter`` maintains a queue for each command internally, and it
+will pop a response off of the corresponding queue each time it
+processes a request.
+
+Note that you have to call ``seed_response`` once for each request you
+expect it to process. If ``MockAdapter`` does not have a seeded response
+for a particular command, it will raise a ``BadApiResponse`` exception
+(simulates a 404 response).
+
+Wrappers
+--------
+
+Wrappers act like decorators for adapters; they are used to enhance or
+otherwise modify the behavior of adapters.
+
+RoutingWrapper
+~~~~~~~~~~~~~~
+
+.. code:: python
+
+ from iota import Iota
+ from iota.adapter.wrappers import RoutingWrapper
+
+ api =\
+ Iota(
+ # Send PoW requests to local node.
+ # All other requests go to light wallet node.
+ RoutingWrapper('https://service.iotasupport.com:14265')
+ .add_route('attachToTangle', 'http://localhost:14265')
+ .add_route('interruptAttachingToTangle', 'http://localhost:14265')
+ )
+
+``RoutingWrapper`` allows you to route API requests to different nodes
+depending on the command name.
+
+For example, you could use this wrapper to direct all PoW requests to a
+local node, while sending the other requests to a light wallet node.
+
+``RoutingWrapper`` must be initialized with a default URI/adapter. This
+is the adapter that will be used for any command that doesn't have a
+route associated with it.
+
+Once you've initialized the ``RoutingWrapper``, invoke its ``add_route``
+method to specify a different adapter to use for a particular command.
+
+``add_route`` requires two arguments:
+
+- ``command: Text``: The name of the command. Note that this is the
+ camelCase version of the command name (e.g., ``getNodeInfo``, not
+ ``get_node_info``).
+- ``adapter: AdapterSpec``: The adapter or URI to send this request to.
diff --git a/docs/addresses.rst b/docs/addresses.rst
new file mode 100644
index 00000000..6571e7f2
--- /dev/null
+++ b/docs/addresses.rst
@@ -0,0 +1,140 @@
+Generating Addresses
+====================
+
+In IOTA, addresses are generated deterministically from seeds. This
+ensures that your account can be accessed from any location, as long as
+you have the seed.
+
+Note that this also means that anyone with access to your seed can spend
+your IOTAs! Treat your seed(s) the same as you would the password for
+any other financial service.
+
+.. note::
+
+ PyOTA's crytpo functionality is currently very slow; on average it takes
+ 8-10 seconds to generate each address.
+
+ These performance issues will be fixed in a future version of the library;
+ please bear with us!
+
+ In the meantime, if you are using Python 3, you can install a C extension
+ that boosts PyOTA's performance significantly (speedups of 60x are common!).
+
+ To install the extension, run ``pip install pyota[ccurl]``.
+
+ **Important:** The extension is not yet compatible with Python 2.
+
+ If you are familiar with Python 2's C API, we'd love to hear from you!
+ Check the `GitHub issue `_
+ for more information.
+
+PyOTA provides two methods for generating addresses:
+
+Using the API
+-------------
+
+.. code:: python
+
+ from iota import Iota
+
+ api = Iota('http://localhost:14265', b'SEED9GOES9HERE')
+
+ # Generate 5 addresses, starting with index 0.
+ gna_result = api.get_new_addresses(count=5)
+ addresses = gna_result['addresses']
+
+ # Generate 1 address, starting with index 42:
+ gna_result = api.get_new_addresses(start=42)
+ addresses = gna_result['addresses']
+
+ # Find the first unused address, starting with index 86:
+ gna_result = api.get_new_addresses(start=86, count=None)
+ addresses = gna_result['addresses']
+
+To generate addresses using the API, invoke its ``get_new_addresses``
+method, using the following parameters:
+
+- ``start: int``: The starting index (defaults to 0). This can be used
+ to skip over addresses that have already been generated.
+- ``count: Optional[int]``: The number of addresses to generate
+ (defaults to 1).
+- If ``None``, the API will generate addresses until it finds one that
+ has not been used (has no transactions associated with it on the
+ Tangle). It will then return the unused address and discard the rest.
+- ``security_level: int``: Determines the security level of the
+ generated addresses. See `Security Levels <#security-levels>`__
+ below.
+
+``get_new_addresses`` returns a dict with the following items:
+
+- ``addresses: List[Address]``: The generated address(es). Note that
+ this value is always a list, even if only one address was generated.
+
+Using AddressGenerator
+----------------------
+
+.. code:: python
+
+ from iota.crypto.addresses import AddressGenerator
+
+ generator = AddressGenerator(b'SEED9GOES9HERE')
+
+ # Generate a list of addresses:
+ addresses = generator.get_addresses(start=0, count=5)
+
+ # Generate a list of addresses in reverse order:
+ addresses = generator.get_addresses(start=42, count=10, step=-1)
+
+ # Create an iterator, advancing 5 indices each iteration.
+ iterator = generator.create_iterator(start=86, step=5)
+ for address in iterator:
+ ...
+
+If you want more control over how addresses are generated, you can use
+the ``AddressGenerator`` class.
+
+``AddressGenerator`` can create iterators, allowing your application to
+generate addresses as needed, instead of having to generate lots of
+addresses up front.
+
+You can also specify an optional ``step`` parameter, which allows you to
+skip over multiple addresses between iterations... or even iterate over
+addresses in reverse order!
+
+``AddressGenerator`` provides two methods:
+
+- ``get_addresses: (int, int, int) -> List[Address]``: Returns a list
+ of addresses. This is the same method that the ``get_new_addresses``
+ API command uses internally.
+- ``create_iterator: (int, int) -> Generator[Address]``: Returns an
+ iterator that will create addresses endlessly. Use this if you have a
+ feature that needs to generate addresses "on demand".
+
+Security Levels
+===============
+
+.. code:: python
+
+ gna_result = api.get_new_addresses(security_level=3)
+
+ generator =\
+ AddressGenerator(
+ seed = b'SEED9GOES9HERE',
+ security_level = 3,
+ )
+
+If desired, you may change the number of iterations that
+``AddressGenerator`` uses internally when generating new addresses, by
+specifying a different ``security_level`` when creating a new instance.
+
+``security_level`` should be between 1 and 3, inclusive. Values outside
+this range are not supported by the IOTA protocol.
+
+Use the following guide when deciding which security level to use:
+
+- ``security_level=1``: Least secure, but generates addresses the
+ fastest.
+- ``security_level=2``: Default; good compromise between speed and
+ security.
+- ``security_level=3``: Most secure; results in longer signatures in
+ transactions.
diff --git a/docs/api.rst b/docs/api.rst
new file mode 100644
index 00000000..9073b166
--- /dev/null
+++ b/docs/api.rst
@@ -0,0 +1,311 @@
+Standard API
+============
+
+The Standard API includes all of the core API calls that are made
+available by the current `IOTA Reference
+Implementation `__.
+
+These methods are "low level" and generally do not need to be called
+directly.
+
+For the full documentation of all the Standard API calls, please refer
+to the `official documentation `__.
+
+Extended API
+============
+
+The Extended API includes a number of "high level" commands to perform
+tasks such as sending and receiving transfers.
+
+``broadcast_and_store``
+-----------------------
+
+Broadcasts and stores a set of transaction trytes.
+
+Parameters
+~~~~~~~~~~
+
+- ``trytes: Iterable[TransactionTrytes]``: Transaction trytes.
+
+Return
+~~~~~~
+
+This method returns a ``dict`` with the following items:
+
+- ``trytes: List[TransactionTrytes]``: Transaction trytes that were
+ broadcast/stored. Should be the same as the value of the ``trytes``
+ parameter.
+
+``get_account_data``
+--------------------
+
+More comprehensive version of ``get_transfers`` that returns addresses
+and account balance in addition to bundles.
+
+This function is useful in getting all the relevant information of your
+account.
+
+Parameters
+~~~~~~~~~~
+
+- ``start: int``: Starting key index.
+
+- ``stop: Optional[int]``: Stop before this index. Note that this
+ parameter behaves like the ``stop`` attribute in a ``slice`` object;
+ the stop index is *not* included in the result.
+
+- If ``None`` (default), then this method will check every address
+ until it finds one without any transfers.
+
+- ``inclusion_states: bool`` Whether to also fetch the inclusion states
+ of the transfers. This requires an additional API call to the node,
+ so it is disabled by default.
+
+Return
+~~~~~~
+
+This method returns a dict with the following items:
+
+- ``addresses: List[Address]``: List of generated addresses. Note that
+ this list may include unused addresses.
+
+- ``balance: int``: Total account balance. Might be 0.
+
+- ``bundles: List[Bundles]``: List of bundles with transactions to/from
+ this account.
+
+``get_bundles``
+---------------
+
+Given a ``TransactionHash``, returns the bundle(s) associated with it.
+
+Parameters
+~~~~~~~~~~
+
+- ``transaction: TransactionHash``: Hash of a tail transaction.
+
+Return
+~~~~~~
+
+This method returns a ``dict`` with the following items:
+
+- ``bundles: List[Bundle]``: List of matching bundles. Note that this
+ value is always a list, even if only one bundle was found.
+
+``get_inputs``
+--------------
+
+Gets all possible inputs of a seed and returns them with the total
+balance.
+
+This is either done deterministically (by generating all addresses until
+``find_transactions`` returns an empty result), or by providing a key
+range to search.
+
+Parameters
+~~~~~~~~~~
+
+- ``start: int``: Starting key index. Defaults to 0.
+- ``stop: Optional[int]``: Stop before this index.
+- Note that this parameter behaves like the ``stop`` attribute in a
+ ``slice`` object; the stop index is *not* included in the result.
+- If ``None`` (default), then this method will not stop until it finds
+ an unused address.
+- ``threshold: Optional[int]``: If set, determines the minimum
+ threshold for a successful result:
+- As soon as this threshold is reached, iteration will stop.
+- If the command runs out of addresses before the threshold is reached,
+ an exception is raised.
+- If ``threshold`` is 0, the first address in the key range with a
+ non-zero balance will be returned (if it exists).
+- If ``threshold`` is ``None`` (default), this method will return
+ **all** inputs in the specified key range.
+
+Note that this method does not attempt to "optimize" the result (e.g.,
+smallest number of inputs, get as close to ``threshold`` as possible,
+etc.); it simply accumulates inputs in order until the threshold is met.
+
+Return
+~~~~~~
+
+This method returns a ``dict`` with the following items:
+
+- ``inputs: List[Address]``: Addresses with nonzero balances that can
+ be used as inputs.
+- ``totalBalance: int``: Aggregate balance of all inputs found.
+
+``get_latest_inclusion``
+------------------------
+
+Fetches the inclusion state for the specified transaction hashes, as of
+the latest milestone that the node has processed.
+
+Parameters
+~~~~~~~~~~
+
+- ``hashes: Iterable[TransactionHash]``: Iterable of transaction
+ hashes.
+
+Return
+~~~~~~
+
+This method returns a ``dict`` with the following items:
+
+- ``: bool``: Inclusion state for a single
+ transaction.
+
+There will be one item per transaction hash in the ``hashes`` parameter.
+
+``get_new_addresses``
+---------------------
+
+Generates one or more new addresses from the seed.
+
+Parameters
+~~~~~~~~~~
+
+- ``index: int``: Specify the index of the new address (must be >= 1).
+- ``count: Optional[int]``: Number of addresses to generate (must be >=
+ 1).
+- If ``None``, this method will scan the Tangle to find the next
+ available unused address and return that.
+- ``security_level: int``: Number of iterations to use when generating
+ new addresses. Lower values generate addresses faster, higher values
+ result in more secure signatures in transactions.
+
+Return
+~~~~~~
+
+This method returns a ``dict`` with the following items:
+
+- ``addresses: List[Address]``: The generated address(es). Note that
+ this value is always a list, even if only one address was generated.
+
+``get_transfers``
+-----------------
+
+Returns all transfers associated with the seed.
+
+Parameters
+~~~~~~~~~~
+
+- ``start: int``: Starting key index.
+- ``stop: Optional[int]``: Stop before this index.
+- Note that this parameter behaves like the ``stop`` attribute in a
+ ``slice`` object; the stop index is *not* included in the result.
+- If ``None`` (default), then this method will check every address
+ until it finds one without any transfers.
+
+Return
+~~~~~~
+
+This method returns a ``dict`` with the following items:
+
+- ``bundles: List[Bundle]``: Matching bundles, sorted by tail
+ transaction timestamp.
+
+``prepare_transfer``
+--------------------
+
+Prepares transactions to be broadcast to the Tangle, by generating the
+correct bundle, as well as choosing and signing the inputs (for value
+transfers).
+
+Parameters
+~~~~~~~~~~
+
+- ``transfers: Iterable[ProposedTransaction]``: Transaction objects to
+ prepare.
+- ``inputs: Optional[Iterable[Address]]``: List of addresses used to
+ fund the transfer. Ignored for zero-value transfers.
+- If not provided, addresses will be selected automatically by scanning
+ the Tangle for unspent inputs.
+- ``change_address: Optional[Address]``: If inputs are provided, any
+ unspent amount will be sent to this address.
+- If not specified, a change address will be generated automatically.
+
+Return
+~~~~~~
+
+This method returns a ``dict`` with the following items:
+
+- ``trytes: List[TransactionTrytes]``: Raw trytes for the transactions
+ in the bundle, ready to be provided to ``send_trytes``.
+
+``replay_bundle``
+-----------------
+
+Takes a tail transaction hash as input, gets the bundle associated with
+the transaction and then replays the bundle by attaching it to the
+Tangle.
+
+Parameters
+~~~~~~~~~~
+
+- ``transaction: TransactionHash``: Transaction hash. Must be a tail.
+- ``depth: int``: Depth at which to attach the bundle.
+- ``min_weight_magnitude: Optional[int]``: Min weight magnitude, used
+ by the node to calibrate Proof of Work.
+- If not provided, a default value will be used.
+
+Return
+~~~~~~
+
+This method returns a ``dict`` with the following items:
+
+- ``trytes: List[TransactionTrytes]``: Raw trytes that were published
+ to the Tangle.
+
+``send_transfer``
+-----------------
+
+Prepares a set of transfers and creates the bundle, then attaches the
+bundle to the Tangle, and broadcasts and stores the transactions.
+
+Parameters
+~~~~~~~~~~
+
+- ``depth: int``: Depth at which to attach the bundle.
+- ``transfers: Iterable[ProposedTransaction]``: Transaction objects to
+ prepare.
+- ``inputs: Optional[Iterable[Address]]``: List of addresses used to
+ fund the transfer. Ignored for zero-value transfers.
+- If not provided, addresses will be selected automatically by scanning
+ the Tangle for unspent inputs.
+- ``change_address: Optional[Address]``: If inputs are provided, any
+ unspent amount will be sent to this address.
+- If not specified, a change address will be generated automatically.
+- ``min_weight_magnitude: Optional[int]``: Min weight magnitude, used
+ by the node to calibrate Proof of Work.
+- If not provided, a default value will be used.
+
+Return
+~~~~~~
+
+This method returns a ``dict`` with the following items:
+
+- ``bundle: Bundle``: The newly-published bundle.
+
+``send_trytes``
+---------------
+
+Attaches transaction trytes to the Tangle, then broadcasts and stores
+them.
+
+Parameters
+~~~~~~~~~~
+
+- ``trytes: Iterable[TransactionTrytes]``: Transaction trytes to
+ publish.
+- ``depth: int``: Depth at which to attach the bundle.
+- ``min_weight_magnitude: Optional[int]``: Min weight magnitude, used
+ by the node to calibrate Proof of Work.
+- If not provided, a default value will be used.
+
+Return
+~~~~~~
+
+This method returns a ``dict`` with the following items:
+
+- ``trytes: List[TransactionTrytes]``: Raw trytes that were published
+ to the Tangle.
diff --git a/docs/index.rst b/docs/index.rst
index 625e1baa..8eb81e68 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -4,6 +4,9 @@
getting_started
types
+ adapters
+ addresses
+ api
.. note::
**🚧 PyOTA documentation is still under construction. 🚧**
diff --git a/docs/types.rst b/docs/types.rst
index aa9b54e8..f8f6cbdd 100644
--- a/docs/types.rst
+++ b/docs/types.rst
@@ -1,264 +1,355 @@
-================
-PyOTA Data Types
-================
-.. important::
+Basic Concepts
+==============
- Before diving into the API, it's important to understand the fundamental data
- types of IOTA.
+Before diving into the API, it's important to understand the fundamental
+data types of IOTA.
- For an introduction to the IOTA protocol and the Tangle, give the
- `protocol documentation`_ a once-over.
+:todo: Link to IOTA docs
-PyOTA defines a few types that will make it easy for you to model objects like
-Transactions and Bundles in your own code.
+PyOTA Types
+===========
+
+PyOTA defines a few types that will make it easy for you to model
+objects like Transactions and Bundles in your own code.
TryteString
-----------
-A :py:class:`TryteString` is an ASCII representation of a sequence of trytes.
-In many respects, it is similar to a Python ``bytes`` object (which is an ASCII
-representation of a sequence of bytes).
-
-In fact, the two objects behave very similarly; they support concatenation,
-comparison, can be used as dict keys, etc.
-
-However, unlike ``bytes``, a :py:class:`TryteString` can only contain uppercase
-letters and the number 9 (as a regular expression: ``^[A-Z9]*$``).
-
-.. admonition:: Why only these characters?
-
- You can find the answer on the
- `IOTA Forum `__.
-
-As you go through the API documentation, you will see many references to
-:py:class:`TryteString` and its subclasses:
-
-- :py:class:`Fragment`
-
- A signature or message fragment inside a transaction.
- Fragments are always 2187 trytes long.
-- :py:class:`Hash`
+.. code:: python
- An object identifier. Hashes are always 81 trytes long.
+ from iota import TryteString
- There are many different types of hashes:
+ trytes_1 = TryteString(b'RBTC9D9DCDQAEASBYBCCKBFA')
+ trytes_2 = TryteString(b'LH9GYEMHCF9GWHZFEELHVFOEOHNEEEWHZFUD')
- :py:class:`Address`
- Identifies an address on the Tangle.
- :py:class:`BundleHash`
- Identifies a bundle on the Tangle.
- :py:class:`TransactionHash`
- Identifies a transaction on the Tangle.
+ if trytes_1 != trytes_2:
+ trytes_combined = trytes_1 + trytes_2
-- :py:class:`Seed`
+ index = {
+ trytes_1: 42,
+ trytes_2: 86,
+ }
- A TryteString that is used for crypto functions such as generating addresses,
- signing inputs, etc.
+A ``TryteString`` is an ASCII representation of a sequence of trytes. In
+many respects, it is similar to a Python ``bytes`` object (which is an
+ASCII representation of a sequence of bytes).
- .. important::
+In fact, the two objects behave very similarly; they support
+concatenation, comparison, can be used as dict keys, etc.
- Seeds can be any length, but 81 trytes offers the best security.
- More information is available on the
- `IOTA Forum `__.
-
-- :py:class:`Tag`
-
- A tag used to classify a transaction. Tags are always 27 trytes long.
-
-- :py:class:`TransactionTrytes`
-
- A TryteString representation of a transaction on the Tangle.
- :py:class:`TransactionTrytes` are always 2673 trytes long.
-
-Creating TryteStrings
-~~~~~~~~~~~~~~~~~~~~~
-To create a new :py:class:`TryteString` from a sequence of trytes, simply
-wrap the trytes inside the :py:class:`TryteString` initializer:
-
-.. code-block:: python
-
- from iota import TryteString
-
- trytes = TryteString('RBTC9D9DCDQAEASBYBCCKBFA')
+However, unlike ``bytes``, a ``TryteString`` can only contain uppercase
+letters and the number 9 (as a regular expression: ``^[A-Z9]*$``).
-To encode ASCII text into trytes, use the :py:meth:`TryteString.from_string`
-method:
+As you go through the API documentation, you will see many references to
+``TryteString`` and its subclasses:
-.. code-block:: python
+- ``Fragment``: A signature or message fragment inside a transaction.
+ Fragments are always 2187 trytes long.
+- ``Hash``: An object identifier. Hashes are always 81 trytes long.
+ There are many different types of hashes:
+- ``Address``: Identifies an address on the Tangle.
+- ``BundleHash``: Identifies a bundle on the Tangle.
+- ``TransactionHash``: Identifies a transaction on the Tangle.
+- ``Seed``: A TryteString that is used for crypto functions such as
+ generating addresses, signing inputs, etc. Seeds can be any length,
+ but 81 trytes offers the best security.
+- ``Tag``: A tag used to classify a transaction. Tags are always 27
+ trytes long.
+- ``TransactionTrytes``: A TryteString representation of a transaction
+ on the Tangle. ``TransactionTrytes`` are always 2673 trytes long.
- from iota import TryteString
+Encoding
+~~~~~~~~
- message_trytes = TryteString.from_string('Hello, IOTA!')
+.. code:: python
- print(message_trytes) # RBTC9D9DCDQAEASBYBCCKBFA
+ from iota import TryteString
-To decode a sequence of trytes back into ASCII text, use
-:py:meth:`TryteString.as_string`:
+ message_trytes = TryteString.from_string('Hello, IOTA!')
-.. code-block:: python
+To encode character data into trytes, use the
+``TryteString.from_string`` method.
- from iota import TryteString
+You can also convert a tryte sequence into characters using
+``TryteString.as_string``. Note that not every tryte sequence can be
+converted; garbage in, garbage out!
- message_trytes = TryteString('RBTC9D9DCDQAEASBYBCCKBFA')
+.. code:: python
- message_str = message_trytes.as_string()
+ from iota import TryteString
- print(message_str) # Hello, IOTA!
+ trytes = TryteString(b'RBTC9D9DCDQAEASBYBCCKBFA')
+ message = trytes.as_string()
.. note::
- PyOTA also supports encoding non-ASCII characters, but this functionality is
- **experimental** and has not yet been standardized.
+ PyOTA also supports encoding non-ASCII characters, but this functionality is
+ **experimental** and has not yet been evaluated by the IOTA
+ community!
- If you encode non-ASCII characters, be aware that other IOTA libraries
- (possibly including future versions of PyOTA!) might not be able to decode
- them!
+ Until this feature has been standardized, it is recommended that you only
+ use ASCII characters when generating ``TryteString`` objects from
+ character strings.
Transaction Types
-----------------
-PyOTA defines two different types used to represent transactions:
-
-:py:class:`Transaction`
- A transaction that has been loaded from the Tangle.
-:py:class:`ProposedTransaction`
- A transaction that was created locally and hasn't been broadcast to the
- Tangle yet.
+PyOTA defines two different types used to represent transactions:
Transaction
~~~~~~~~~~~
-Generally, you will never need to create `Transaction` objects; the API will
-build them for you, as the result of various API methods.
-
-.. tip::
-
- If you have a TryteString representation of a transaction, and you'd like to
- convert it into a :py:class:`Transaction` object, use the
- :py:meth:`Transaction.from_tryte_string` method:
-
- .. code-block:: python
-
- from iota import Transaction
-
- txn_1 =\
- Transaction.from_tryte_string(
- 'GYPRVHBEZOOFXSHQBLCYW9ICTCISLHDBNMMVYD9JJHQMPQCTIQ...',
- )
-
- This is equivalent to the `Paste Trytes`_ feature from the IOTA Wallet.
-
-Each :py:class:`Transaction` object has the following attributes:
-
-- ``address`` (:py:class:`Address`)
-
- The address associated with this transaction. Depending on the transaction's
- ``value``, this address may be a sender or a recipient.
-
-- ``attachment_timestamp`` (:py:class:`int`)
- Timestamp after completing the Proof of Work process.
-
- See the `timestamps white paper`_ for more information.
-
-- ``attachment_timestamp_lower_bound`` (:py:class:`int`)
- Lower bound of the timestamp.
-
- See the `timestamps white paper`_ for more information.
-
-- ``attachment_timestamp_upper_bound`` (:py:class:`int`)
- Upper bound of the timestamp.
- See the `timestamps white paper`_ for more information.
-
-- ``branch_transaction_hash`` (:py:class:`TransactionHash`)
-
- An unrelated transaction that this transaction "approves".
- Refer to the `protocol documentation`_ for more information.
-
-- ``bundle_hash`` (:py:class:`BundleHash`)
-
- The bundle hash, used to identify transactions that are part of the same
- bundle. This value is generated by taking a hash of the metadata from all
- transactions in the bundle.
-
-- ``current_index`` (:py:class:`int`)
-
- The transaction's position in the bundle.
-
- - If the ``current_index`` value is 0, then this is the "tail transaction".
- - If it is equal to ``last_index``, then this is the "head transaction".
-
-- ``hash`` (:py:class:`TransactionHash`)
-
- The transaction hash, used to uniquely identify the transaction on the
- Tangle. This value is generated by taking a hash of the raw transaction
- trytes.
-
-- ``last_index`` (:py:class:`int`)
-
- The index of the final transaction in the bundle. This value is attached to
- every transaction to make it easier to traverse and verify bundles.
-
-- ``nonce`` (:py:class:`Nonce`)
-
- This is the product of the PoW process.
-
- Refer to the `protocol documentation`_ for more information.
-
-- ``signature_message_fragment`` (:py:class:`Fragment`)
-
- Additional data attached to the transaction:
-
- - If ``value < 0``, this value contains a fragment of the cryptographic
- signature authorizing the spending of the IOTAs.
- - If ``value > 0``, this value is an (optional) string message attached to
- the transaction.
- - If ``value = 0``, this value could be either a signature or message
- fragment, depending on the previous transaction.
-
- .. tip::
-
- Read this as "Signature/Message Fragment". That is, it could be a
- fragment of a signature **or** a message, depending on the transaction.
-
-- ``tag`` (:py:class:`Tag`)
-
- Used to classify the transaction.
-
- Every transaction has a tag, but many transactions have empty tags.
-
-- ``timestamp`` (:py:class:`int`)
-
- Unix timestamp when the transaction was created.
-
- Note that devices can specify any timestamp when creating transactions, so
- this value is not safe to use by itself for security measures (such as
- resolving double-spends).
-
- .. note::
-
- The IOTA protocol does support verifiable timestamps. Refer to the
- `timestamps white paper`_ for more information.
-
-- ``trunk_transaction_hash`` (:py:class:`TransactionHash`)
-
- The transaction hash of the next transaction in the bundle.
-
- If this transaction is the head transaction, its ``trunk_transaction_hash``
- will be pseudo-randomly selected, similarly to ``branch_transaction_hash``.
-
-- ``value`` (:py:class:`int`)
-
- The number of IOTAs being transferred in this transaction:
-
- - If this value is negative, then the ``address`` is spending IOTAs.
- - If it is positive, then the ``address`` is receiving IOTAs.
- - If it is zero, then this transaction is being used to carry metadata (such
- as a signature fragment or a message) instead of transferring IOTAs.
-
-
-:todo: ProposedTransaction
+.. code:: python
+
+ from iota import Address, ProposedTransaction, Tag, Transaction
+
+ txn_1 =\
+ Transaction.from_tryte_string(
+ b'GYPRVHBEZOOFXSHQBLCYW9ICTCISLHDBNMMVYD9JJHQMPQCTIQAQTJNNNJ9IDXLRCC'
+ b'OYOXYPCLR9PBEY9ORZIEPPDNTI9CQWYZUOTAVBXPSBOFEQAPFLWXSWUIUSJMSJIIIZ'
+ b'WIKIRH9GCOEVZFKNXEVCUCIIWZQCQEUVRZOCMEL9AMGXJNMLJCIA9UWGRPPHCEOPTS'
+ b'VPKPPPCMQXYBHMSODTWUOABPKWFFFQJHCBVYXLHEWPD9YUDFTGNCYAKQKVEZYRBQRB'
+ b'XIAUX9SVEDUKGMTWQIYXRGSWYRK9SRONVGTW9YGHSZRIXWGPCCUCDRMAXBPDFVHSRY'
+ b'WHGB9DQSQFQKSNICGPIPTRZINYRXQAFSWSEWIFRMSBMGTNYPRWFSOIIWWT9IDSELM9'
+ b'JUOOWFNCCSHUSMGNROBFJX9JQ9XT9PKEGQYQAWAFPRVRRVQPUQBHLSNTEFCDKBWRCD'
+ b'X9EYOBB9KPMTLNNQLADBDLZPRVBCKVCYQEOLARJYAGTBFR9QLPKZBOYWZQOVKCVYRG'
+ b'YI9ZEFIQRKYXLJBZJDBJDJVQZCGYQMROVHNDBLGNLQODPUXFNTADDVYNZJUVPGB9LV'
+ b'PJIYLAPBOEHPMRWUIAJXVQOEM9ROEYUOTNLXVVQEYRQWDTQGDLEYFIYNDPRAIXOZEB'
+ b'CS9P99AZTQQLKEILEVXMSHBIDHLXKUOMMNFKPYHONKEYDCHMUNTTNRYVMMEYHPGASP'
+ b'ZXASKRUPWQSHDMU9VPS99ZZ9SJJYFUJFFMFORBYDILBXCAVJDPDFHTTTIYOVGLRDYR'
+ b'TKHXJORJVYRPTDH9ZCPZ9ZADXZFRSFPIQKWLBRNTWJHXTOAUOL9FVGTUMMPYGYICJD'
+ b'XMOESEVDJWLMCVTJLPIEKBE9JTHDQWV9MRMEWFLPWGJFLUXI9BXPSVWCMUWLZSEWHB'
+ b'DZKXOLYNOZAPOYLQVZAQMOHGTTQEUAOVKVRRGAHNGPUEKHFVPVCOYSJAWHZU9DRROH'
+ b'BETBAFTATVAUGOEGCAYUXACLSSHHVYDHMDGJP9AUCLWLNTFEVGQGHQXSKEMVOVSKQE'
+ b'EWHWZUDTYOBGCURRZSJZLFVQQAAYQO9TRLFFN9HTDQXBSPPJYXMNGLLBHOMNVXNOWE'
+ b'IDMJVCLLDFHBDONQJCJVLBLCSMDOUQCKKCQJMGTSTHBXPXAMLMSXRIPUBMBAWBFNLH'
+ b'LUJTRJLDERLZFUBUSMF999XNHLEEXEENQJNOFFPNPQ9PQICHSATPLZVMVIWLRTKYPI'
+ b'XNFGYWOJSQDAXGFHKZPFLPXQEHCYEAGTIWIJEZTAVLNUMAFWGGLXMBNUQTOFCNLJTC'
+ b'DMWVVZGVBSEBCPFSM99FLOIDTCLUGPSEDLOKZUAEVBLWNMODGZBWOVQT9DPFOTSKRA'
+ b'BQAVOQ9RXWBMAKFYNDCZOJGTCIDMQSQQSODKDXTPFLNOKSIZEOY9HFUTLQRXQMEPGO'
+ b'XQGLLPNSXAUCYPGZMNWMQWSWCKAQYKXJTWINSGPPZG9HLDLEAWUWEVCTVRCBDFOXKU'
+ b'ROXH9HXXAXVPEJFRSLOGRVGYZASTEBAQNXJJROCYRTDPYFUIQJVDHAKEG9YACV9HCP'
+ b'JUEUKOYFNWDXCCJBIFQKYOXGRDHVTHEQUMHO999999999999999999999999999999'
+ b'999999999999999999999999999999999999999999999999999999999999999999'
+ b'999999999999999999999999999999999999999999999999999999999999999999'
+ b'999999999999999999999999999999999999999999999999999999999999999999'
+ b'999999999999999999999999999999999999999999999999999999999999999999'
+ b'999999999999999999999999999999999999999999999999999999999999999999'
+ b'999999999999999999999999999999999999999999999999999999999999999999'
+ b'999999999999999999999999999999999999999999999999999999999999999999'
+ b'999999999999999999999999999999999999999999999999999999999999999999'
+ b'999999999999999999999999999999999999999999999999999999999999999999'
+ b'999999999999999999999999999999999999999999999999999999999999999999'
+ b'999999999999RKWEEVD99A99999999A99999999NFDPEEZCWVYLKZGSLCQNOFUSENI'
+ b'XRHWWTZFBXMPSQHEDFWZULBZFEOMNLRNIDQKDNNIELAOXOVMYEI9PGTKORV9IKTJZQ'
+ b'UBQAWTKBKZ9NEZHBFIMCLV9TTNJNQZUIJDFPTTCTKBJRHAITVSKUCUEMD9M9SQJ999'
+ b'999TKORV9IKTJZQUBQAWTKBKZ9NEZHBFIMCLV9TTNJNQZUIJDFPTTCTKBJRHAITVSK'
+ b'UCUEMD9M9SQJ999999999999999999999999999999999999999999999999999999'
+ b'999999999999999999999999999999999'
+ )
+
+``Transaction`` is a transaction that has been loaded from the Tangle.
+
+Generally, you will never need to create ``Transaction`` objects; the
+API will build them for you, as the result of various API methods.
+
+Each ``Transaction`` has the following attributes:
+
+- ``address: Address``: The address associated with this transaction.
+ Depending on the transaction's ``value``, this address may be a
+ sender or a recipient.
+- ``branch_transaction_hash: TransactionHash``: An unrelated
+ transaction that this transaction "approves". Refer to the Basic
+ Concepts section for more information.
+- ``bundle_hash: BundleHash``: The bundle hash, used to identify
+ transactions that are part of the same bundle. This value is
+ generated by taking a hash of the metadata from all transactions in
+ the bundle.
+- ``current_index: int``: The transaction's position in the bundle.
+- If the ``current_index`` value is 0, then this is the "tail
+ transaction".
+- If it is equal to ``last_index``, then this is the "head
+ transaction".
+- ``hash: TransactionHash``: The transaction hash, used to uniquely
+ identify the transaction on the Tangle. This value is generated by
+ taking a hash of the raw transaction trits.
+- ``is_confirmed: Optional[bool]``: Whether this transaction has been
+ "confirmed". Refer to the Basic Concepts section for more
+ information.
+- ``last_index: int``: The index of the final transaction in the
+ bundle. This value is attached to every transaction to make it easier
+ to traverse and verify bundles.
+- ``nonce: Hash``: This is the product of the PoW process.
+- ``signature_message_fragment: Fragment``: Additional data attached to
+ the transaction:
+- If ``value < 0``, this value contains a fragment of the cryptographic
+ signature authorizing the spending of the IOTAs.
+- If ``value > 0``, this value is an (optional) string message attached
+ to the transaction.
+- If ``value = 0``, this value could be either a signature or message
+ fragment, depending on the previous transaction.
+- ``tag: Tag``: Used to classify the transaction. Many transactions
+ have empty tags (``Tag(b'999999999999999999999999999')``).
+- ``timestamp: int``: Unix timestamp when the transaction was created.
+ Note that devices can specify any timestamp when creating
+ transactions, so this value is not safe to use for security measures
+ (such as resolving double-spends).
+- ``trunk_transaction_hash: TransactionHash``: The transaction hash of
+ the next transaction in the bundle. If this transaction is the head
+ transaction, its ``trunk_transaction_hash`` will be pseudo-randomly
+ selected, similarly to ``branch_transaction_hash``.
+- ``value: int``: The number of IOTAs being transferred in this
+ transaction:
+- If this value is negative, then the ``address`` is spending IOTAs.
+- If it is positive, then the ``address`` is receiving IOTAs.
+- If it is zero, then this transaction is being used to carry metadata
+ (such as a signature fragment or a message) instead of transferring
+ IOTAs.
+
+ProposedTransaction
+~~~~~~~~~~~~~~~~~~~
+
+``ProposedTransaction`` is a transaction that was created locally and
+hasn't been broadcast yet.
+
+.. code:: python
+
+ txn_2 =\
+ ProposedTransaction(
+ address =
+ Address(
+ b'TESTVALUE9DONTUSEINPRODUCTION99999XE9IVG'
+ b'EFNDOCQCMERGUATCIEGGOHPHGFIAQEZGNHQ9W99CH'
+ ),
+
+ message = TryteString.from_string('thx fur cheezburgers'),
+ tag = Tag(b'KITTEHS'),
+ value = 42,
+ )
+
+This type is useful when creating new transactions to broadcast to the
+Tangle. Note that creating a ``ProposedTransaction`` requires only a
+small subset of the attributes needed to create a ``Transaction``
+object.
+
+To create a ``ProposedTransaction``, specify the following values:
+
+- ``address: Address``: The address associated with the transaction.
+ Note that each transaction references exactly one address; in order
+ to transfer IOTAs from one address to another, you must create at
+ least two transactions: One to deduct the IOTAs from the sender's
+ balance, and one to add the IOTAs to the recipient's balance.
+- ``message: Optional[TryteString]``: Optional trytes to attach to the
+ transaction. This could be any value (character strings, binary data,
+ or raw trytes), as long as it's converted to a ``TryteString`` first.
+- ``tag: Optional[Tag]``: Optional tag to classify this transaction.
+ Each transaction may have exactly one tag, and the tag is limited to
+ 27 trytes.
+- ``value: int``: The number of IOTAs being transferred in this
+ transaction. This value can be 0; for example, to send a message
+ without spending any IOTAs.
+
+Bundle Types
+------------
+
+As with transactions, PyOTA defines two bundle types.
+
+Bundle
+~~~~~~
+
+.. code:: python
+
+ from iota import Bundle
+
+ bundle = Bundle.from_tryte_strings([
+ b'GYPRVHBEZOOFXSHQBLCYW9ICTCISLHDBNMMVYD9JJHQMPQCTIQAQTJNNNJ9IDXLRCC...',
+ b'OYOXYPCLR9PBEY9ORZIEPPDNTI9CQWYZUOTAVBXPSBOFEQAPFLWXSWUIUSJMSJIIIZ...',
+ # etc.
+ ])
+
+``Bundle`` represents a bundle of transactions published on the Tangle.
+It is intended to be a read-only object, allowing you to inspect the
+transactions and bundle metadata.
+
+Each bundle has the following attributes:
+
+- ``hash: BundleHash``: The hash of this bundle. This value is
+ generated by taking a hash of the metadata from all transactions in
+ the bundle.
+- ``is_confirmed: Optional[bool]``: Whether the transactions in this
+ bundle have been confirmed. Refer to the Basic Concepts section for
+ more information.
+- ``tail_transaction: Optional[Transaction]``: The bundle's tail
+ transaction.
+- ``transactions: List[Transaction]``: The transactions associated with
+ this bundle.
+
+ProposedBundle
+~~~~~~~~~~~~~~
+
+.. code:: python
+
+ from iota import Address, ProposedBundle, ProposedTransaction
+ from iota.crypto.signing import KeyGenerator
+
+ bundle = ProposedBundle()
+
+ bundle.add_transaction(ProposedTransaction(...))
+ bundle.add_transaction(ProposedTransaction(...))
+ bundle.add_transaction(ProposedTransaction(...))
+
+ bundle.add_inputs([
+ Address(
+ address =
+ b'TESTVALUE9DONTUSEINPRODUCTION99999HAA9UA'
+ b'MHCGKEUGYFUBIARAXBFASGLCHCBEVGTBDCSAEBTBM',
+
+ balance = 86,
+ key_index = 0,
+ ),
+ ])
+
+ bundle.send_unspent_inputs_to(
+ Address(
+ b'TESTVALUE9DONTUSEINPRODUCTION99999D99HEA'
+ b'M9XADCPFJDFANCIHR9OBDHTAGGE9TGCI9EO9ZCRBN'
+ ),
+ )
+
+ bundle.finalize()
+ bundle.sign_inputs(KeyGenerator(b'SEED9GOES9HERE'))
+.. note::
-.. _protocol documentation: https://iota.readme.io/docs/
-.. _paste trytes: https://forum.iota.org/t/3457/3
-.. _timestamps white paper: https://iota.org/timestamps.pdf
+ This section contains information about how PyOTA works "under the
+ hood".
+
+ The ``prepare_transfer`` API method encapsulates this functionality
+ for you; it is not necessary to understand how ``ProposedBundle``
+ works in order to use PyOTA.
+
+
+``ProposedBundle`` provides a convenient interface for creating new
+bundles, listed in the order that they should be invoked:
+
+- ``add_transaction: (ProposedTransaction) -> None``: Adds a
+ transaction to the bundle. If necessary, it may split the transaction
+ into multiple (for example, if the transaction's message is too long
+ to fit into 2187 trytes).
+- ``add_inputs: (List[Address]) -> None``: Specifies inputs that can be
+ used to fund transactions that spend IOTAs. The ``ProposedBundle``
+ will use these to create the necessary input transactions.
+- You can use the ``get_inputs`` API command to find suitable inputs.
+- ``send_unspent_inputs_to: (Address) -> None``: Specifies the address
+ that will receive unspent IOTAs. The ``ProposedBundle`` will use this
+ to create the necessary change transaction, if necessary.
+- ``finalize: () -> None``: Prepares the bundle for PoW. Once this
+ method is invoked, no new transactions may be added to the bundle.
+- ``sign_inputs: (KeyGenerator) -> None``: Generates the necessary
+ cryptographic signatures to authorize spending the inputs. You do not
+ need to invoke this method if the bundle does not contain any
+ transactions that spend IOTAs.
+
+Once the ``ProposedBundle`` has been finalized (and inputs signed, if
+necessary), invoke its ``as_tryte_strings`` method to generate the raw
+trytes that should be included in an ``attach_to_tangle`` API request.