コード例 #1
0
import time
import logging
import sys
sys.path.append(
    "/home/pi/.local/lib/python2.7/site-packages"
)  #path muss hinzugefügt werden damit PyOta librarys gefunden werden können

from iota import Iota, ProposedTransaction, ProposedBundle, Address, Tag, TryteString  #importe Iota-Bibliothek um die API anzusprechen
from iota.crypto.addresses import AddressGenerator

# Reciever Seed: GCUKFZRLCTBGBDKQCQY9SMJPDPLFBDJJFTXZANHDJUTCZKIQQEUHSAVOYWKPTDDNEWRGBFWDMWYYRLRUR
# returned Address at index 0 for Security Level 2
reciever_address = "LOZMZOKJWWVASYYWT999JPLDBMUSFZKMLZW9IXHTOAUOQKZMRLRAZCWECAFONWKT9HSHKHLMKAWSQFFXX"

seed = "DSPOAXMVSC99IUIVJXTIBZFATVFKTCLLJYOLAGSMFJGFXAWEB9GNTQWEDVRYHKIOQF9T9IZY9IVPKTSZK"
url = "https://potato.iotasalad.org:14265"  #fullnode url
api = Iota(url, seed)  #erstelle Iota API
logging.basicConfig(format='%(levelname)s:%(message)s', level=logging.DEBUG)
logger = logging.getLogger(__name__)
api.adapter.set_logger(logger)

proposedTrx = ProposedTransaction(
    address=Address(reciever_address),
    value=0,
    tag=Tag("BACHELORTEST"),
    message=TryteString.from_string("This is a test transaction"))

proposedBundle = ProposedBundle([proposedTrx])
preparedBundle = api.prepare_transfer(proposedBundle)
publishedBundle = api.send_transfer(depth=3, transfers=proposedBundle)
コード例 #2
0
# Send PoW requests to local node.
# All other requests go to light wallet node.
router = RoutingWrapper('http://service.iotasupport.com:14265')
router.add_route('attachToTangle', 'http://localhost:14265')

api = Iota(router, seed=b'SEED9GOES9HERE')

# Example of sending a transfer using the adapter.
bundle = api.send_transfer(
    depth=3,
    transfers=[
        ProposedTransaction(
            # Recipient of the transfer.
            address=Address(
                # b'TESTVALUE9DONTUSEINPRODUCTION99999FBFFTG'
                # b'QFWEHEL9KCAFXBJBXGE9HID9XCOHFIDABHDG9AHDR'
            ),

            # Amount of IOTA to transfer.
            # This value may be zero.
            value=1,

            # Optional tag to attach to the transfer.
            tag=Tag(b'ADAPT'),

            # Optional message to include with the transfer.
            message=TryteString.from_string('Hello!'),
        ),
    ],
)
コード例 #3
0
ファイル: escrow.py プロジェクト: d1aboilik/iotaworkshop
class Escrow:
    def __init__(self, node='https://nodes.thetangle.org:443', seed=None):
        #Get Seed
        if seed is None:
            self.seed = self.getSeed()
        else:
            self.seed = seed

        #Setup API
        self.api = Iota(node, self.seed)

    #Generates a seed for escrow account
    def getSeed(self):
        #If no seed, create one
        if not os.path.isfile('seed.txt'):
            path = pathlib.Path(__file__).parent.absolute()
            seed = ''.join([random.choice(LETTERS) for i in range(81)])
            open('seed.txt', 'w+').write(seed)
            logging.info("Placed new seed in seed.txt")
        return open('seed.txt').read().strip().encode('utf-8')

    #Creates an escrow holding address
    def createEscrow(self):
        try:
            self.holdingAddress = self.api.get_new_addresses(
                count=None, checksum=True)['addresses'][0]
        except iota.adapter.BadApiResponse as e:
            logging.warning("Bad response from server retrying.")
            return self.createEscrow()
        return self.holdingAddress

    #Waits for a transactions with a refund address
    def getRefundAddress(self):
        #This is the escrow address
        address = self.holdingAddress
        try:
            #Get Hashes from ledger
            txHashes = self.api.find_transactions(addresses=[
                address,
            ])['hashes']
            #If no hashes, user has not submitted an address yet.
            if len(txHashes) == 0:
                return None
            else:
                #Check messages for a valid address
                txs = self.api.get_transaction_objects(
                    txHashes)['transactions']
                for tx in txs:
                    msg = tx.signature_message_fragment.decode()
                    try:
                        self.deposit = Address(msg.strip())
                        return self.deposit
                    except:
                        pass
                logging.warning("Invalid address recieved")
        except requests.exceptions.ConnectionError as e:
            #Sometimes the public nodes will reject a request
            print("Error contacting server; retrying")
            return self.getRefundAddress()

    #Cli version of escrow
    def startCli(self, collateral, fee=0, delay=120, deposit=None):
        #Create holding address
        self.createEscrow()
        self.fee = fee
        self.collateral = collateral
        #Wait for a deposit address to be entered
        if self.requestDeposit(collateral, deposit, delay):
            while not self.checkCondition():
                sleep(3)
        self.finalizeEscrow()

    #Wait for escrow address to recieve collateral
    def requestDeposit(self, collateral, deposit=None, duration=120):
        #For CLI prompt a deposit address
        if deposit is None:
            self.deposit = input("What is the deposit address: ")
        print(
            f"You have {duration/60:.1f} min to deposit {collateral} IOTA to {self.holdingAddress}"
        )

        #Wait for escrow to recive collateral funds.
        count = 0
        while count < duration:
            time.sleep(1)
            balance = self.getBalance(self.holdingAddress)
            if balance >= collateral:
                print("Successfully deposited into escrow", balance)
                return True
        return False

    #Condition to release escrow
    def checkCondition(self):
        #Setup a check condition
        #For example RFID or some ledger condition
        return True

    #Refund user their collateral, remoing the fee
    def finalizeEscrow(self, fee=None, deposit=None):
        if fee is None: fee = self.fee
        if deposit is None: deposit = self.deposit
        #Return money to deposit address
        returnAmount = self.getBalance(self.holdingAddress)

        #Calcualte return amount
        if returnAmount > 0:
            returnAmount -= fee

        #Setup transaction
        message = "Repayment of collateral"
        feeLocation = self.api.get_new_addresses(count=1,
                                                 checksum=True)['addresses'][0]
        txs = [
            ProposedTransaction(address=Address(deposit),
                                value=returnAmount,
                                message=TryteString.from_unicode(message)),
        ]

        #Send transaction
        try:
            bundle = self.api.send_transfer(transfers=txs)['bundle']
        except iota.adapter.BadApiResponse as e:
            print("Node did not respond. Retrying.")
            return self.finalizeEscrow(fee, deposit)
        logging.info(bundle.transactions[0].hash)
        logging.info("Sent money back to recipient")
        self.addRevenue(fee)

    def getBalance(self, address):
        try:
            response = self.api.get_balances(addresses=[address])['balances']
            return response[0]
        except requests.exceptions.ConnectionError as e:
            logging.info("Error contacting server; retrying")
            return self.getBalance(self, address)

    #Record the amount of revenue recieved
    def addRevenue(self, money, filename='revenue.txt'):
        if not os.path.isfile(filename):
            open(filename, 'w+').write('0')
        current = int(open(filename).read().strip())
        current += money
        open(filename, 'w+').write(str(current))

    #Get the current amount of revenue
    def getRevenue(self, filename="revenue.txt"):
        if not os.path.isfile(filename): return 0
        return int(open(filename).read().strip())

    #Send revenue to an address
    def sendRevenue(self, outputAddress):
        revenue = self.getRevenue()
        logger.info(f"Currently have {revenue} revenue.")
        message = "Output fees from escrow."
        txs = [
            ProposedTransaction(address=Address(outputAddress),
                                value=revenue,
                                message=TryteString.from_unicode(message)),
        ]
        try:
            logger.info("Sending transfer to node.")
            bundle = self.api.send_transfer(transfers=txs)['bundle']
        except iota.adapter.BadApiResponse as e:
            print("Bad api resonse retrying")
            return self.sendRevenue(outputAddress)
        print(bundle.transactions[0].hash)
コード例 #4
0
        'YCXCVQDFGWUKPUABPYNMVPAQUGUHYYLMWZQWRUIDIXGTDAOJKOUGRWDJUUOWGOHMVYLTZHGEZCZHBTMT9RM9XGRJUW'
    ]
}]

for account in accounts:
    # fetch seed
    seed = account['seed']
    fund = account['fund']
    addrs = account['addresses']
    # log
    print '[%s] Start' % (seed)
    # setup iota client
    api = Iota('http://localhost:14265', seed)
    # attach each address
    for address in addrs:
        # prepare trx
        trx = ProposedTransaction(address=Address(address),
                                  message=TryteString.from_string(
                                      "MSG%s%s" % (seed[:5], address[:5])),
                                  tag=Tag("TAG%s%s" % (seed[:5], address[:5])),
                                  value=0)
        # attach
        api.send_transfer(1, [trx])
    # ensure we can get the expected amount of funding for that account now
    api_fund = api.get_account_data(0)['balance']
    if api_fund == fund:
        print '[%s] Success' % (seed)
    else:
        print '[%s] Fail: expected %d IOTA, got %d IOTA' % (seed, fund,
                                                            api_fund)
コード例 #5
0
ファイル: 02_send_data.py プロジェクト: watertim/iota.py
from iota import Iota, TryteString, Address, Tag, ProposedTransaction
from pprint import pprint

# Declare an API object
api = Iota('https://nodes.devnet.iota.org:443', devnet=True)

# Prepare custom data
my_data = TryteString.from_unicode('Hello from the Tangle!')

# Generate a random address that doesn't have to belong to anyone
my_address = Address.random()

# Tag is optional here
my_tag = Tag(b'MY9FIRST9TAG')

# Prepare a transaction object
tx = ProposedTransaction(
    address=my_address,
    value=0,
    tag=my_tag,
    message=my_data
)

# Send the transaction to the network
response = api.send_transfer([tx])

pprint('Check your transaction on the Tangle!')
pprint('https://utils.iota.org/transaction/%s/devnet' % response['bundle'][0].hash)
コード例 #6
0
class MyIOTA:
    def __init__(self, node, seed):
        self.node = node
        self.seed = seed
        self.api = False
        self._update = False
        self.transfers = []
        self._debug = False

        self.wallet = self.get_filename()

        self.addr_dict = {}

        self.min_weight_magnitude = 14

        self.api = Iota(self.node, self.seed)

        self.USED = True
        self.NOT_USED = False

    def get_addr_dict(self):
        return self.addr_dict

    def set_addr_dict(self, addr, value, used):
        self.addr_dict[addr] = (value, used)

    def s_addr(self, addr, n=3):
        s_addr = str(addr)
        l = len(s_addr)

        return s_addr[:n] + '...' + s_addr[l - n:]

    def get_filename(self):
        h = hashlib.sha256()
        h.update(self.seed)
        filename = h.hexdigest()[:20] + '.txt'

        return filename

    def init_wallet(self):
        filename = self.wallet

        # file exists
        if os.path.isfile(filename):
            filefd = open(filename, 'r+')

            self.debug(
                'Wallet file {0} exists. Opening it...'.format(filename))

            for line in filefd:
                line = line.rstrip('\n')

                addr, index, value, used = line.split(',')

                self.debug('reading from file: {0},{1},{2}'.format(
                    self.s_addr(addr, 3), value, used))

                used = used == 'True'

                addr = Address(addr, key_index=int(index), security_level=2)
                self.addr_dict[addr] = (int(index), int(value), used)

            filefd.close()
        else:
            filefd = open(filename, 'w')
            self.debug('Wallet file {0} doesnt exist. Creating it...'.format(
                filename))
            filefd.close()

    def is_empty_wallet(self):
        return len(self.addr_dict) == 0

    def get_fund_inputs(self, inputs):
        total_fund = 0

        for addr in inputs:
            index, value, used = self.addr_dict[addr]

            # TODO: abs. is this right?
            total_fund += abs(value)

        return total_fund

    def write_updates(self):
        filefd = open(self.wallet, 'w')

        self.debug('Writing (updating) wallet...')

        for addr in self.addr_dict:
            v = self.addr_dict[addr]

            line = 'Writing: {0},{1},{2},{3}\n'.format(self.s_addr(addr), v[0],
                                                       v[1], v[2])
            self.debug(line)

            filefd.write('{0},{1},{2},{3}\n'.format(addr, v[0], v[1], v[2]))

        filefd.close()

    def update_wallet(self, input_fund, inputs, change_addr):
        copy_dict = self.addr_dict.copy()

        for addr in inputs:
            v = self.addr_dict[addr]
            #self.debug('Spending {0} from input {1}'.format(self.s_addr(addr), v))

            # Negative fund and used address
            new_value = (v[0], -v[1], not v[2])

            self.debug('Updating input address {0} to: {1}'.format(
                self.s_addr(addr), new_value))

            self.addr_dict[addr] = new_value

        change_fund = self.get_fund_inputs(inputs) - input_fund

        v = self.addr_dict[change_addr]
        change_value = (v[0], change_fund, self.NOT_USED)

        self.debug('Updating change address {0} to: {1}'.format(
            self.s_addr(change_addr), change_value))

        self.addr_dict[change_addr] = change_value

        self.write_updates()

    def enable_debug(self):
        self._debug = True

    def debug(self, msg):
        if self._debug:
            print '[+] Debug: ', msg

    def get_node_info(self):
        self.api.get_node_info()

    def make_addr_list(self, start_index, n):
        self.iota_assert(start_index >= 0 and n > 0,
                         'must be positive numbers. N should be at least 1.')

        result = self.api.get_new_addresses(index=start_index, count=n)
        addresses = result['addresses']

        for i in range(n):
            addr = addresses[i]
            value = self.get_addr_balance(addr)

            # TODO: Why always False
            self.addr_dict[addr] = (i, value, False)

    def get_addr_balance(self, addr):
        # TODO: addr is a list with just one element
        result = self.api.get_balances([addr])

        balance = result['balances']

        return (balance[0])

    def prepare_transfer(self,
                         transfer_value,
                         dest_addr,
                         tag='DEFAULT',
                         msg='DEFAULT'):
        # TODO: verify address (checksum)
        # TODO: use mi, gi, etc

        msg = TryteString.from_string(msg)

        txn = ProposedTransaction(
            address=Address(dest_addr),
            message=msg,
            tag=Tag(tag),
            value=transfer_value,
        )

        return txn

    def find_transactions(self):
        addr_list = []
        for e in self.addr_dict.items():
            addr = e[0]

            addr_list.append(addr)

        return self.api.findTransactions(addresses=addr_list)['hashes']

    def get_bundle(self, trans):
        return self.api.getBundles(transaction=trans)

    def get_latest_inclusion(self, addrl):
        return self.api.get_latest_inclusion(hashes=addrl)

    def get_total_fund(self):
        total_fund = 0

        for addr in self.addr_dict.items():
            # key and value from dict
            k, v = addr

            print k, v

            index, value, used = v

            #if not used:
            total_fund += value

        return total_fund

    def send_transfer(self, input_fund, inputs, outputs, change_addr):
        iota.debug('Sending {0} transactions, please wait...'.format(
            len(outputs)))

        #self.update_wallet(input_fund, inputs, change_addr)
        #return

        self.api.send_transfer(inputs=inputs,
                               depth=7,
                               transfers=outputs,
                               change_address=change_addr,
                               min_weight_magnitude=self.min_weight_magnitude)

        self.update_wallet(input_fund, inputs, change_addr)

    def get_trytes(self, hashl):
        return self.api.get_trytes(hashl)['trytes'][0]

    def get_transaction_from_trytes(self, trytes):
        txn = Transaction.from_tryte_string(trytes)

        return txn

    def get_transaction_fields(self, txn):
        #print dir(txn)

        confirmed = str(txn.is_confirmed)
        timestamp = str(txn.timestamp)
        address = str(txn.address)
        value = str(txn.value)
        message = str(txn.signature_message_fragment)
        #message   = str(txn.message)
        tag = str(txn.tag)

        return (confirmed, timestamp, address, value, tag, message)

    def get_info_transactions(self, transactions_hashes):
        txn_tuples = []

        for h in transactions_hashes:
            trytes = iota.get_trytes([h])
            txn = iota.get_transaction_from_trytes(trytes)

            (_, _, addr_t, value_t, tag_t,
             msg_t) = iota.get_transaction_fields(txn)

            txn_tuples.append((addr_t, value_t, tag_t, msg_t))
            #txn_tuples.append((tag_t, msg_t))

        return txn_tuples

    def get_inputs(self, fund, get_change_addr=False):
        # TODO: Zero fund
        fund_sum = 0
        addr_list = []
        change_addr = None

        for e in self.addr_dict.items():
            addr, v = e
            index, value, used = v

            if fund_sum < fund:
                #if value > 0 and not used:
                if value > 0 and used == self.NOT_USED:
                    fund_sum += value
                    iota.debug(
                        'Found request: {0}. Found address {1} with fund {2}.'.
                        format(fund, iota.s_addr(addr), value))
                    addr_list.append(addr)

        if get_change_addr:
            for e in self.addr_dict.items():
                addr, v = e
                index, value, used = v

                if used == self.NOT_USED and addr not in addr_list:
                    change_addr = addr

                    iota.debug('Using {0} as change addr.'.format(
                        iota.s_addr(addr)))
                return (addr_list, change_addr)

            # TODO
            self.iota_assert(True, 'No change addr available.')

        return addr_list

    def iota_assert(self, condition, msg):
        if not condition:
            print 'Error: ', msg
            sys.exit(-1)
コード例 #7
0
from config import SEED, DEPTH, MIN_WEIGHT_MAGNITUDE, NODE_URL

receiver_address = "ILXW9VMJQVFQVKVE9GUZSODEMIMGOJIJNFAX9PPJHYQPUHZLTWCJZKZKCZYKKJJRAKFCCNJN9EWOW9N9YDGZDDQDDC"
txn_tag = "TXNTAGS"
message = {"key": "values"}
value = 0

# Iota instance
api = Iota(NODE_URL, SEED)

# Txn description
txn = ProposedTransaction(
    address=Address(receiver_address),
    message=TryteString.from_string(json.dumps(message)),
    tag=Tag(txn_tag),
    value=value,
)

# Send transaction
prepared_transferes = []
bundle = ""
prepared_transferes.append(txn)
try:
    bundle = api.send_transfer(depth=DEPTH,
                               transfers=prepared_transferes,
                               min_weight_magnitude=MIN_WEIGHT_MAGNITUDE)
except Exception as e:
    print(e)

print(bundle['bundle'].hash)
コード例 #8
0
class IotaCache(object):

    def __init__(self, uri=None, seed=None):
        if not uri:
            self.uri = "http://localhost:14700"
        else:
            self.uri = uri
        if not seed:
            self.seed = 'EBZYNR9YVFIOAZUPQOLRZXPPPIKRCJ9EJKVCXMYVLMNOCCOPYPJKCWUZNLJZZZZWTMVQUXZFYLVLZXJ9Q'
        else:
            self.seed = seed
        self.api = Iota(self.uri, self.seed, testnet=True)
        self.mwm = 1
        self.depth = 15

    def cache_txn_in_tangle_sdk(self, ipfs_addr, tag):
        api_response = self.api.get_new_addresses()
        addy = api_response['addresses'][0]
        address = binary_type(addy).decode('ascii')

        result = self.api.send_transfer(
            depth=self.depth,
            transfers=[
                ProposedTransaction(
                    address=Address(address),
                    value=0,
                    tag=Tag(tag),
                    message=TryteString.from_string(ipfs_addr),
                ),
            ],
            min_weight_magnitude=self.mwm,
        )
        return result

    def cache_txn_in_tangle_simple(self, data, tag):
        address = "JVSVAFSXWHUIZPFDLORNDMASGNXWFGZFMXGLCJQGFWFEZWWOA9KYSPHCLZHFBCOHMNCCBAGNACPIGHVYX"
        txns = self.api.get_transactions_to_approve(self.depth)
        tr = self.api.get_trytes([txns[u'branchTransaction']])
        txn = Transaction.from_tryte_string(tr[u'trytes'][0], txns[u'branchTransaction'])
        txn.trunk_transaction_hash = txns[u'trunkTransaction']
        txn.branch_transaction_hash = txns[u'branchTransaction']
        txn.tag = Tag(TryteString.from_string(tag))
        txn.signature_message_fragment = Fragment(TryteString.from_bytes(data))
        attach_trytes = attachToTangle(self.uri, txns[u'trunkTransaction'].__str__(), txns[u'branchTransaction'].__str__(), 1, txn.as_tryte_string().__str__())
        res = self.api.broadcast_and_store(attach_trytes[u'trytes'])
        return res

    def cache_txn_in_tangle_message(self, data, tag):
        #address = "JVSVAFSXWHUIZPFDLORNDMASGNXWFGZFMXGLCJQGFWFEZWWOA9KYSPHCLZHFBCOHMNCCBAGNACPIGHVYX"
        address = "14dD6ygPi5WXdwwBTt1FBZK3aD8uDem1FY"
        res = storeMessage(self.uri, address, data, tag)
        return res

    def get_balance(self, coin_type, account):
        address = "JVSVAFSXWHUIZPFDLORNDMASGNXWFGZFMXGLCJQGFWFEZWWOA9KYSPHCLZHFBCOHMNCCBAGNACPIGHVYX"
        res = getBalance(self.uri, address, coin_type, account)
        return res

    def get_approved_txns(self, tag):
        ret = []
        transactions = self.api.find_transactions(None, None, [tag], None)
        if len(transactions['hashes']) == 0:
            return ret
        tips = self.api.get_tips()
        states = self.api.get_inclusion_states(transactions['hashes'], tips['hashes'])
        i = 0
        for txn in transactions['hashes']:
            if states['states'][i] is True:
                ret.append(txn)
        return ret

    def get_non_consumed_txns(self, tag):
        ret = []
        txn_hashes_all = self.get_approved_txns(tag)
        if len(txn_hashes_all) == 0:
            return ret
        txn_trytes_all = self.api.get_trytes(txn_hashes_all)
        consumedSet = []
        txn_hashes_consumed = self.api.find_transactions(None, None, [tag+b"CONSUMED"], None)
        if len(txn_hashes_consumed['hashes']) != 0:
            txn_trytes_consumed = self.api.get_trytes(txn_hashes_consumed['hashes'])
            i=0
            for txnTrytes in txn_trytes_consumed['trytes']:
                txn = Transaction.from_tryte_string(txnTrytes, txn_hashes_consumed['hashes'][i])
                i+=1
                consumedSet.append(txn.signature_message_fragment)
        i=0
        for txnTrytes in txn_trytes_all['trytes']:
            txn = Transaction.from_tryte_string(txnTrytes, txn_hashes_all[i])
            i+=1
            if txn.signature_message_fragment not in consumedSet:
                msgTryte = txn.signature_message_fragment.decode()
                ret.append(msgTryte)

        return ret

    def set_txn_as_synced(self, ipfs_addr, tag):
        result = self.cache_txn_in_tangle_sdk(ipfs_addr, tag+b"CONSUMED")
        return result

    def add_neighbors(self, uris):
        res = addNeighbors(self.uri, uris)
        return res

    def get_block_content(self, hashes):
        res = getBlockContent(self.uri, hashes)
        return res

    def get_dag(self, dag_type):
        res = getDAG(self.uri, dag_type)
        return res

    def get_utxo(self, dag_type):
        res = getUTXO(self.uri, dag_type)
        return res

    def get_total_order(self):
        res = getTotalOrder(self.uri)
        return res
コード例 #9
0
ファイル: 05_send_tokens.py プロジェクト: watertim/iota.py
my_seed = Seed(b'YOURSEEDFROMTHEPREVIOUSTUTORIAL')

# Declare an API object
api = Iota(
    adapter='https://nodes.devnet.iota.org:443',
    seed=my_seed,
    devnet=True,
)

# Addres to receive 1i
# Feel free to replace it. For example, run the code from Tutorial 4.a
# and use that newly generated address with a 'fresh' seed.
receiver = Address(
    b'WWUTQBO99YDCBVBPAPVCANW9ATSNUPPLCPGDQXGQEVLUBSFHCEWOA9DIYYOXJONDIRHYPXQXOYXDPHREZ'
)

print('Constructing transfer of 1i...')
# Create the transfer object
tx = ProposedTransaction(
    address=receiver,
    value=1,
    message=TryteString.from_unicode('I just sent you 1i, use it wisely!'),
    tag=Tag('VALUETX'),
)

print('Preparing bundle and sending it to the network...')
# Prepare the transfer and send it to the network
response = api.send_transfer(transfers=[tx])

print('Check your transaction on the Tangle!')
print('https://utils.iota.org/bundle/%s/devnet' % response['bundle'].hash)
コード例 #10
0
class TangleConnector:
    def __init__(self,
                 url='https://perma.iota.partners:443',
                 seed="TESTSEED9"):
        self.iri_url = url
        self.iota_api = Iota(url, seed)

    def get_node(self) -> Dict:
        """
        Get IRI node info
        """
        try:
            res = self.iota_api.get_node_info()
        except BadApiResponse as e:
            logger.warning("Failed to IRI node info for " + self.iri_url, e)
            res = None
        return res

    def get_tips(self) -> Dict:
        """
        Get all unreferenced transactions
        """
        try:
            res = self.iota_api.get_tips()
        except BadApiResponse as e:
            logger.warning("Failed to get tips", e)
            res = None
        return res

    def get_hashes_from_addr(self, address: Address) -> List[TransactionHash]:
        """
        Get all tx from address
        """
        try:
            response = self.iota_api.find_transactions(addresses=[address])
            hashes = response['hashes']
        except (BadApiResponse, KeyError) as e:
            logger.warning(
                "Failed to get all tx from address " + address.__str__(), e)
            hashes = None
        return hashes

    def get_trytes_from_hashes(
            self, hashes: List[TransactionHash]) -> List[TryteString]:
        """
        Get tryte signature fragments from hashes
        """
        try:
            response = self.iota_api.get_trytes(hashes)
            trytes = [tryte[0:2187] for tryte in response['trytes']]
        except (BadApiResponse, KeyError) as e:
            logger.warning("Failed to get all signature fragments", e)
            trytes = None
        return trytes

    def get_all_trytes_from_address(
            self, address: Address) -> Dict[TransactionHash, TryteString]:
        """
        Get all trytes from address
        """
        hashes = self.get_hashes_from_addr(address)
        trytes = self.get_trytes_from_hashes(hashes)
        if hashes and trytes:
            result = dict(zip(hashes, trytes))
        else:
            result = None
        return result

    @staticmethod
    def get_json_from_tryte(tryte: TryteString) -> Dict:
        try:
            str_from_tryte = tryte.as_string()
            dict_from_tryte = json.loads(str_from_tryte)
        except ValueError as e:
            logger.error("Failed to convet trytes to JSON", e)
            dict_from_tryte = None
        return dict_from_tryte

    def send_msg_to_addr(self, address: Address, msg: str, tag: str) -> Dict:
        """
        Sends msg on Tangle to address with a tag
        """
        try:
            response = self.iota_api.send_transfer(
                depth=2,
                transfers=[
                    ProposedTransaction(address=address,
                                        value=0,
                                        tag=Tag(tag),
                                        message=TryteString.from_string(msg))
                ])
        except BadApiResponse as e:
            logger.warning(
                "Message '" + msg + "' has failed to be stored in " +
                address.__str__(), e)
            response = None
        return response

    def get_bundles_from_addr(self, address: Address) -> List[Dict]:
        '''
        Retrive all bundles sent to this address from IRI
        # requres IRI 1.6+ (or it seems so)
        '''
        hashes = self.get_hashes_from_addr(address)
        bundles = []
        if hashes:
            for tx in hashes:
                try:
                    # have to loop through all txs, if tx is not 'tail' of a bundle then get_bundles() throws error
                    bundle = self.iota_api.get_bundles(tx)
                except BadApiResponse:
                    bundle = None

                if bundle:
                    bundles.append(bundle)
        return bundles

    def get_messages_from_bundles(self, bundles: List) -> Dict:
        """
        Loop through list of bundles and get string per bundle
        # requres IRI 1.6+ (or it seems so)
        """
        output_msgs = {}
        for bundle in bundles:
            tx_list = bundle['bundles'][0].as_json_compatible()
            msg = ''
            for tx in tx_list:
                # if its a bundle with iotas, just get text from first tx in bundle, the rest are signatures
                if tx['current_index'] == 0 and tx['value'] > 0:
                    msg = tx['signature_message_fragment'].as_string()
                    break
                # if its a bundle without iota value, then consequently get all message fields and join strings
                if tx['value'] == 0:
                    msg = msg + tx['signature_message_fragment'].as_string()
            bundle_hash = tx_list[0]['bundle_hash'].__str__()
            addr = tx_list[0]['address'].__str__()
            timestamp = tx_list[0]['timestamp']
            value = tx_list[0]['value']
            output_msgs[bundle_hash] = {
                'msg': msg,
                'address': addr,
                'timestamp': timestamp,
                'value': value
            }
        return output_msgs

    def get_all_msg_from_addr_by_bundle(self, address: Address) -> Dict:
        '''
        Get dict of all msg with timestamps from address by bundle hash as key
        # requres IRI 1.6+ (or it seems so)
        '''
        bundles = self.get_bundles_from_addr(address)
        hashes_and_msgs = self.get_messages_from_bundles(bundles)
        return hashes_and_msgs
コード例 #11
0
if __name__ == '__main__':
    parse_cli_arg()
    api = Iota(f'{URL}', testnet=TESTNET)
    txn_array = []
    tag = gen_rand_trytes(27)
    address = []
    message = []
    for i in range(sent_transaction_number):
        address.append(gen_rand_trytes(81))
        message.append(TryteString.from_unicode(f'{payload}, number: {i}'))

        tx_elt = ProposedTransaction(address=Address(address[i]),
                                     tag=tag,
                                     message=message[i],
                                     value=0)
        txn_array.append(api.send_transfer(transfers=[tx_elt]))
        curr_hash = txn_array[i]['bundle'].tail_transaction.hash
        logging.info(
            f'hash: {curr_hash}, address: {address[i]}, tag: {tag}, message: {message[i]}'
        )

    # Get raw transaction trytes
    txn_trytes = []
    txn_hashes = []
    txn_tags = []
    for i in range(sent_transaction_number):
        txn_trytes.append(
            txn_array[i]['bundle'].tail_transaction.as_tryte_string())
        txn_hashes.append(txn_array[i]['bundle'].tail_transaction.hash)
        txn_tags.append(txn_array[i]['bundle'].tail_transaction.tag)
コード例 #12
0
ファイル: iota_cache.py プロジェクト: btellstrom/iri
class IotaCache(object):
    def __init__(self, uri=None, seed=None):
        if not uri:
            self.uri = "http://localhost:14700"
        else:
            self.uri = uri
        if not seed:
            self.seed = 'EBZYNR9YVFIOAZUPQOLRZXPPPIKRCJ9EJKVCXMYVLMNOCCOPYPJKCWUZNLJZZZZWTMVQUXZFYLVLZXJ9Q'
        else:
            self.seed = seed
        self.api = Iota(self.uri, self.seed)

    def cache_txn_in_tangle(self, ipfs_addr, tag):
        api_response = self.api.get_new_addresses()
        addy = api_response['addresses'][0]
        address = binary_type(addy).decode('ascii')

        result = self.api.send_transfer(
            depth=3,
            transfers=[
                ProposedTransaction(
                    address=Address(address),
                    value=0,
                    tag=Tag(tag),
                    message=TryteString.from_string(ipfs_addr),
                ),
            ],
        )
        return result

    def get_approved_txns(self, tag):
        ret = []
        transactions = self.api.find_transactions(None, None, [tag], None)
        if len(transactions['hashes']) == 0:
            return ret
        tips = self.api.get_tips()
        states = self.api.get_inclusion_states(transactions['hashes'],
                                               tips['hashes'])
        i = 0
        for txn in transactions['hashes']:
            if states['states'][i] is True:
                ret.append(txn)
        return ret

    def get_non_consumed_txns(self, tag):
        txn_hashes_all = self.get_approved_txns(tag)
        txn_trytes_all = self.api.get_trytes(txn_hashes_all)
        txn_hashes_consumed = self.api.find_transactions(
            None, None, [tag + b"CONSUMED"], None)
        txn_trytes_consumed = self.api.get_trytes(
            txn_hashes_consumed['hashes'])
        consumedSet = []
        ret = []
        for txnTrytes in txn_trytes_consumed['trytes']:
            txn = Transaction.from_tryte_string(txnTrytes)
            consumedSet.append(txn.signature_message_fragment)
        for txnTrytes in txn_trytes_all['trytes']:
            txn = Transaction.from_tryte_string(txnTrytes)
            if txn.signature_message_fragment not in consumedSet:
                msgTryte = txn.signature_message_fragment.decode()
                ret.append(msgTryte)
        return ret

    def set_txn_as_synced(self, ipfs_addr, tag):
        result = self.cache_txn_in_tangle(ipfs_addr, tag + b"CONSUMED")
        return result
コード例 #13
0
ファイル: test.py プロジェクト: Voulzy/blockc
from iota import Iota, TryteString, Address, Tag, ProposedTransaction
from pprint import pprint

api = Iota('https://nodes.devnet.iota.org:443', testnet=True)

message = TryteString.from_unicode('Hello world')
adress = "ZLGVEQ9JUZZWCZXLWVNTHBDX9G9KZTJP9PREEIIFHY9SIQKYBVAHIMLHXPQVE9IXFDDXNHQINXJDRPFDX"

tag = Tag(b'MY9FIRST9TAG')

tx = ProposedTransaction(address=Address(adress), message=message, value=0)
result = api.send_transfer([tx])

pprint('Check your transaction on the Tangle!')
pprint('https://utils.iota.org/transaction/%s/devnet' %
       result['bundle'][0].hash)

#ZLGVEQ9JUZZWCZXLWVNTHBDX9G9KZTJP9PREEIIFHY9SIQKYBVAHIMLHXPQVE9IXFDDXNHQINXJDRPFDX
コード例 #14
0
from iota import ProposedTransaction
from iota import Address
from iota import Tag
from iota import TryteString
from iota.crypto.types import Seed

node1 = 'https://nodes.comnet.thetangle.org:443'
node2 = 'http://localhost:14265'

seed1 = 'QVZCNIFLUY9GXPGKLY9VTFPFS9PLTFAUQDOHNLVRYJONGAX9TPDXDEJ9OXFR9RRKGFUJNXOJUAATRKNTX'
seed2 = 'TSGVUYISRDCWWOWTIQKPTEUELXKFPCSITBJDCYVLN9LSUYGLWGRGDRJX9SEWIOPXKFUEOXYAXUPPCQFYX'
print('Seed 1 is:', seed1)
print('Seed 2 is:', seed2, '\n')

address1 = 'QVZCNIFLUY9GXPGKLY9VTFPFS9PLTFAUQDOHNLVRYJONGAX9TPDXDEJ9OXFR9RRKGFUJNXOJUAATRKNTX'
address2 = 'TSGVUYISRDCWWOWTIQKPTEUELXKFPCSITBJDCYVLN9LSUYGLWGRGDRJX9SEWIOPXKFUEOXYAXUPPCQFYX'
print('Address 1 is:', address1)
print('Address 2 is:', address2, '\n')

api = Iota(node2, seed1)
security_level = 2

balance = api.get_account_data()
print('The balance of seed1 is: ', balance['balance'])

tx = ProposedTransaction(address=Address(address2), value=500)

result = api.send_transfer(transfers=[tx], min_weight_magnitude=10)
print('Bundle: ')
print(result['bundle'].hash)
コード例 #15
0
        h = blake2b(digest_size=16)
        h_pw = h.update(bytes(secret_key.encode('utf-8')))
        hh = h.hexdigest()
        pw_string = str(hh).encode('utf-8')
        b64_pw = base64.b64encode(pw_string)

        ## Encrypt the Message
        data = {'message': Message}
        msg = json.dumps(data)
        key = b64_pw
        f = Fernet(key)
        token = f.encrypt(bytes(msg.encode('utf-8')))
        msg_data = token.decode('ascii')

        ## Create a Bundle
        pt = ProposedTransaction(address=root_address,
                                 message=TryteString.from_unicode(msg_data),
                                 tag=TAG,
                                 value=0)
        ## Send the Transaction
        FinalBundle = api.send_transfer(depth=3,
                                        transfers=[pt],
                                        min_weight_magnitude=14)['bundle']

        print(new_address)

        root_address = new_address

except KeyboardInterrupt:
    print("Cleanup")
コード例 #16
0
ファイル: dag.py プロジェクト: paolosantancini/aqsm
 def doTransaction(self, message):
     api = Iota(self.api, testnet = True)
     msg = TryteString.from_unicode(message)
     tx = ProposedTransaction(address = Address(self.address),message = msg,value = 0)
     result = api.send_transfer(transfers = [tx])
     return(result['bundle'].tail_transaction.hash)
コード例 #17
0
ファイル: tangle_connector.py プロジェクト: AleBuser/MAMCR
class TangleConnector:
    def __init__(self,
                 url='https://nutzdoch.einfachiota.de',
                 seed="TESTSEED9"):
        self.iri_url = url
        self.iota_api = Iota(url, seed)

    def get_node(self) -> dict:
        """
        Get IRI node info
        """
        try:
            res = self.iota_api.get_node_info()
        except Exception as e:
            logging.warning("Failed to IRI node info for " + self.iri_url, e)
            res = None
        return res

    def get_tips(self) -> dict:
        """
        Get all unreferenced transactions
        """
        try:
            res = self.iota_api.get_tips()
        except Exception as e:
            logging.warning("Failed to get tips", e)
            res = None
        return res

    def get_hashes_from_addr(self, address: Address) -> List[TransactionHash]:
        """
        Get all tx from address
        """
        try:
            response = self.iota_api.find_transactions(addresses=[address])
            hashes = response['hashes']
        except Exception as e:
            logging.warning(
                "Failed to get all tx from address " + address.__str__(), e)
            hashes = None
        return hashes

    def get_trytes_from_hashes(
            self, hashes: List[TransactionHash]) -> List[TryteString]:
        """
        Get tryte signature fragments from hashes
        """
        try:
            response = self.iota_api.get_trytes(hashes)
            if response['trytes']:
                trytes = [tryte[0:2187] for tryte in response['trytes']]
        except Exception:
            #logging.warning("Failed to get all signature fragments")
            trytes = None
        return trytes

    def get_all_trytes_from_address(
            self, address: Address) -> Dict[TransactionHash, TryteString]:
        """
        Get all trytes from address
        """
        hashes = self.get_hashes_from_addr(address)
        trytes = self.get_trytes_from_hashes(hashes)
        if hashes and trytes:
            result = dict(zip(hashes, trytes))
        else:
            result = None
        return result

    @staticmethod
    def get_json_from_tryte(tryte: TryteString) -> dict:
        try:
            str_from_tryte = tryte.as_string()
            dict_from_tryte = json.loads(str_from_tryte)
        except Exception as e:
            logging.error("Failed to convet trytes to JSON", e)
            dict_from_tryte = None
        return dict_from_tryte

    def send_msg_to_addr(self, address: Address, msg: str, tag: str) -> dict:
        """
        Sends msg on Tangle to address with a tag
        """
        try:
            response = self.iota_api.send_transfer(
                depth=5,
                transfers=[
                    ProposedTransaction(address=address,
                                        value=0,
                                        tag=Tag(tag),
                                        message=TryteString.from_string(msg))
                ])
        except Exception as e:
            logging.warning(
                "Message '" + msg + "' has failed to be stored in " +
                address.__str__(), e)
            response = None
        return response
コード例 #18
0
# check balance of account
balance = api.get_account_data()
print(balance)
#addresses = []
#addresses.append('SVCSKJPIIAOOSAAYMS9HKQVSIRVCKGOFNVQRTEXJNBFMCYFDIEWWYXBWZQDSKNJCVXCQGS9GUJLBHEAVBNS9UNPGFB')
#balances = api.get_balances(addresses, None)
#print(balances)

# address for output transaction
address = 'OCARSUKVZEZJUKSQU9RIKLANCKHDGCZGELJUUISZTAWQAUXSHHD9RJTKKM9ZMDNDZYFKEBKHEXHBPFAED'

tx = ProposedTransaction(address=Address(address),
                         value=10,
                         message=TryteString.from_unicode(testdata))

result = api.send_transfer(transfers=[tx])
print('Bundle: ')
print(result['bundle'])
'''
#////////////////////////////////////////////////
#// Generate an unspent address
#////////////////////////////////////////////////

from iota import Iota

# The seed that will be used to generate an address
seed = 'CVBCQHX9MUZZBZAZGOO9GYHWYBEZRMTWNXKBQHNSFETKUPHKHRGUYWLTSGXYAQEVLNI9XTQPTZAGOIUZH'

# Connect to a node
api = Iota('https://nodes.devnet.iota.org:443', seed, testnet = True)
コード例 #19
0
def detct():
    # for i in range(101):
    if GPIO.input(M_pin):
        motion = 'Someone is closing'
        #print ("Someone is closing!")
        # buzzer(M_pin)
    else:

        GPIO.output(B_pin, GPIO.HIGH)
        motion = 'Nobody Here'
        #print ("Nobody!")
        # time.sleep(2)

    t, h = dt11()

    s = smoke()
    f = flame()

    #data = 'Temp: ' + str(t) + '\xb0 | Humi: ' + str(h)+'% | Gas: ' + s+' | Flame: '+ f +' | Motion: ' + motion
    data = 'Temp: ' + str(t) + '  | Humi: ' + str(h) + '  | Gas: ' + \
        s + '  | Flame: ' + f + '  | Motion: ' + motion
    #data = 'abcd'

    api = Iota('https://nodes.devnet.iota.org:443', testnet=True)

    #address = Address.random(81)
    address = Address(
        'YEQFOMPOTSQXIDGVULITXSXHQOSRLJIUZB9LKTXRHUM9IHYLWYXZTBMLBZRATRFPUVRVRMSYZPDRMWNMQCTGMTRGSZ'
    )

    ######
    ######

    my_data = TryteString.from_unicode(data)

    # Define a zero-value transaction object
    # that sends the message to the address
    tx = ProposedTransaction(address=address, message=my_data, value=0)

    print('Attaching to IOTA')

    result = api.send_transfer(transfers=[tx])
    txn_hash = result['bundle'].tail_transaction.hash

    print('Attached')

    print('Transaction Hash:', txn_hash)
    # time.sleep(.5)

    print('Retriving from IOTA')

    bundle = api.get_bundles(txn_hash)
    message = bundle['bundles'][0].tail_transaction.signature_message_fragment

    output = message.decode()

    print('Message:', output)
    print('https://explorer.iota.org/devnet/address/' + str(address))
    exp = output.split(' ')

    if s == 'Gas Leakage' or f == 'Fire! Fire!!' or motion == 'Someone is closing':
        buzzer(True)
コード例 #20
0
# read file and send each line to the tangle
import json

from iota import Address, Iota, ProposedTransaction, TryteString

with open("tangle/config/address_dump.conf") as in_file:
    ADDRESS = in_file.read().rstrip("\n").encode()

api = Iota("https://durian.iotasalad.org:14265")
receiver = Address(ADDRESS)

with open("pitangle/current_measurements.csv") as f:
    lis = [line.rstrip("\n\r").split(",")
           for line in f]  # create a list of lists
    for i, x in enumerate(lis):
        (idx, humidity, ts, temp) = x  # print the list items
        print(idx)
        measurment = {
            "humidity": humidity,
            "temperature": temp,
            "measuredAt": ts
        }
        message = TryteString.from_string(json.dumps(measurment))
        tx = ProposedTransaction(address=receiver, value=0, message=message)
        api.send_transfer(depth=1, transfers=[tx])
コード例 #21
0
class Wallet:
    """docstring for Wallet"""
    def __init__(self, uri: str, seed: Optional[str] = None) -> None:
        self._iota_api = Iota(uri, seed)
        self._account: _Account

    @property
    def account(self) -> _Account:
        try:
            return self._account
        except AttributeError:
            # We get an attibute error if we check this property before ever
            # calling refresh_account.
            self.refresh_account()
            return self._account

    @property
    def addresses(self) -> List[Address]:
        return self.account.addresses

    @property
    def balance(self) -> int:
        return self.account.balance

    @property
    def bundles(self) -> Dict[str, Iterable[Bundle]]:
        return {
            'confirmed': self.account.confirmed_bundles,
            'unconfirmed': self.account.unconfirmed_bundles,
            'duplicate': self.account.duplicate_bundles,
        }

    def _is_above_max_depth(self, transaction: Transaction) -> bool:
        current_millis = time.time() * 1000
        max_age = 11 * 60 * 1000  # 11 minutes
        diff = current_millis - cast(float, transaction.attachment_timestamp)
        return (0 < diff < max_age)

    def _is_promotable(self, bundle: Bundle) -> bool:
        return (self._is_above_max_depth(bundle.tail_transaction)
                and self._iota_api.helpers.is_promotable(
                    bundle.tail_transaction.hash))

    def _promote(self, bundle: Bundle) -> Bundle:
        tail_hash = bundle.tail_transaction.hash
        response = self._iota_api.get_latest_inclusion([tail_hash])
        if response['states'][tail_hash]:
            raise BundleAlreadyPromoted()

        response = self._iota_api.promote_transaction(transaction=tail_hash,
                                                      depth=DEPTH)
        return response['bundle']

    def _reattach(self, bundle: Bundle) -> Bundle:
        response = self._iota_api.replay_bundle(
            bundle.tail_transaction.hash,
            DEPTH,
        )
        return Bundle.from_tryte_strings(response['trytes'])

    def create_new_address(self) -> Address:
        response = self._iota_api.get_new_addresses(count=None)
        address = response['addresses'][0]

        # Attach the address
        self._iota_api.send_transfer(
            depth=DEPTH,
            transfers=[ProposedTransaction(address, value=0)],
        )

        return address

    def refresh_account(self) -> None:
        response = self._iota_api.get_account_data(inclusion_states=True)
        addresses = response['addresses']
        balance = response['balance']
        bundles = response['bundles']

        self._account = _Account(addresses, balance, bundles)

    def retry_unconfirmed_bundles(self, *bundles: Bundle) -> None:
        if len(bundles) == 0:
            bundles = tuple(self.bundles['unconfirmed'])
        for bundle in bundles:
            print(f'Retrying bundle: {bundle.hash}')
            if not self._is_promotable(bundle):
                bundle = self._reattach(bundle)
                while True:
                    time.sleep(2)
                    if self._is_promotable(bundle):
                        break
            for attempt in range(5):
                try:
                    promote_bundle = self._promote(bundle)
                except BundleAlreadyPromoted:
                    break
                else:
                    print(
                        f'Promotion attempt ({attempt}): Bundle {promote_bundle.hash}'
                    )

    def send(self, address: str, value: int) -> None:
        print(f'Sending {value} iota to {address}...')
        response = self._iota_api.send_transfer(
            depth=DEPTH,
            transfers=[ProposedTransaction(Address(address), value=value)])
        bundle = response['bundle']
        print(f'Iota sent! Bundle hash: {bundle.hash}')
コード例 #22
0
class IotaClient(object):
    """Python IOTA client wrapper"""
    def __init__(self, seed, provider, depth=5, min_weight_magnitude=14):
        self._api = Iota(provider, seed)
        self._depth = depth
        self._min_weight_magnitude = min_weight_magnitude
        self.address = self._get_address()

    @staticmethod
    def _compose_transaction(address, msg, tag, val):
        txn = \
            ProposedTransaction(
                address=Address(address),
                message=TryteString.from_unicode(msg),
                tag=Tag(tag),
                value=val
            )
        return txn

    def _get_address(self):
        address = self._api.get_new_addresses(0, 1)['addresses'][0]
        return str(address)

    def get_transactions_from_address(self, address):
        """
        Gets transaction object from address sorted on timestamp (from latest
        to earliest).

        :param address:
           Address to fetch transaction from

        """
        transactions = self._api.find_transactions(addresses=[address])
        transaction_hashes = transactions['hashes']

        if not transaction_hashes:
            raise ValueError("No transactions on address")

        trytes = self._api.get_trytes(transaction_hashes)['trytes']

        trytes_and_hashes = list(zip(trytes, transaction_hashes))

        transactions = list(
            map(lambda pair: Transaction.from_tryte_string(pair[0], pair[1]),
                trytes_and_hashes))

        sorted_transactions = sorted(transactions,
                                     key=lambda t: t.timestamp,
                                     reverse=True)

        return sorted_transactions

    def get_messages_from_address(self, address):
        """
        Gets messages (sorted by timestamp).
        Returns a dict with 'json_message' and 'timestamp keys'

        :param address:
           Address to fetch messages from

        """
        sorted_transactions = self.get_transactions_from_address(address)
        messages = list(
            map(
                lambda t: {
                    'json_message':
                    json.loads(Fragment.as_string(t.signature_message_fragment)
                               ),
                    'timestamp':
                    t.timestamp
                }, sorted_transactions))

        return messages

    @staticmethod
    def get_message(transaction):
        message = transaction['signature_message_fragment'].decode()
        json_message = json.loads(message)
        return json_message

    def send_transaction(self, address, msg, tag, val):
        txn = self._compose_transaction(Address(address), msg, tag, val)
        mwm = self._min_weight_magnitude
        depth = self._depth
        self._api.send_transfer(depth, [txn], None, None, mwm)
コード例 #23
0
    address=Address(
        b'ADDRESS9GOES9HERE99999999999999999999999999999999999TESTVALUE9DONTUSEINPRODUCTION'
    ),

    # Amount of Iota you want to send
    value=1,

    # Optional Tag (27-trytes)
    tag=Tag(b'ROUTING9WRAPPER9WORKS'),

    # Message (2187-trytes)
    message=TryteString.from_string(
        'I used iota.adapter.wrappers.RoutingWrapper.'))

bundle.add_transaction(output)
"""
A ProposedBundle is a Bundle that is not yet attached to the Tangle.
A ProposedTransaction is a Transaction that is not yet attached to the Tangle.
"""

print("Sending transfer...")

response = API.send_transfer(3, bundle)

print('Bundle Hash: ' + response['bundle'].hash.as_json_compatible())
"""
The API.send_transfer function will take care of signing and inserting the
input transaction and remainder transaction.
I'm printing the bundle hash which can be used for reattaching if necessary.
"""