示例#1
0
def xrp_transfer(order):
    """
    pretty wrap the asyncio xrp transfer
    """
    # FIXME log this event
    timestamp()
    line_number()
    print("\nORDER\n\n", {k: v for k, v in order.items() if k != "private"}, "\n")
    event = asyncio.get_event_loop().run_until_complete(xrp_transfer_execute(order))
    print(it("red", "XRP TRANSFERRED"))
    return event
def eos_transfer(order):
    """
    serialize, sign, and broadcast an order dictionary with nine keys
    """
    # FIXME log this event
    timestamp()
    line_number()
    print("\nORDER\n\n", {k: v for k, v in order.items() if k != "private"}, "\n")
    nodes = eosio_nodes()
    while 1:
        nodes.append(nodes.pop(0))
        node = nodes[0]
        # configure the url and port
        eosio_config.url = node
        eosio_config.port = ""
        print("\nADDRESS\n\n", node, "\n")
        # assemble the transfer operation dictionary
        operation = {
            "from": order["public"],
            "memo": "",
            # eos must have 4 decimal places formatted as string with space and "EOS"
            "quantity": precisely(order["quantity"], 4) + " EOS",
            "to": order["to"],
        }
        print("\nOPERATION\n\n", operation, "\n")
        # serialize the transfer operation
        raw = RawinputParams(
            "transfer",  # the operation type
            operation,  # the parameters
            "eosio.token",  # the contract; for our purposes always "eosio.token"
            order["public"] + "@active",  # the permitted party (or @owner)
        )
        print("\nSERIALIZE\n\n", raw.params_actions_list, "\n")
        # sign the transfer operation
        params = EosioParams(raw.params_actions_list, order["private"])
        print("\nSIGN\n\n", params.trx_json, "\n")
        # broadcast the transfer to the network
        try:
            ret = NodeNetwork.push_transaction(params.trx_json)
            print("\nBROADCAST\n\n", ret)
            if "processed" not in ret.keys():
                raise ValueError("NOT PROCESSED")
            print(it("red", "EOS TRANSFERRED"))
            break
        except Exception as error:
            print(error)
            print(it("red", "BROADCAST FAILED"), node, "attempting new api...")
            continue
    return ret
def verify_ripple_account(account):
    """
    ripple public api consensus of get_account() returns True or False on existance
    """
    data = json_dumps({
        "method":
        "account_info",
        "params": [{
            "account": account,
            "strict": True,
            "ledger_index": "current",
            "queue": True,
        }],
    })
    ret = get(URL, data=data).json()["result"]
    timestamp()
    line_number()
    print(ret, "\n")
    is_account = False
    if "account_data" in ret.keys():
        is_account = True
    return is_account
def recycler():
    """
    in a background process, check incoming accounts & move funds to outbound accounts
    """
    networks = ["eos", "xrp"]
    print(it("red", f"INITIALIZING RECYCLER\n"), "networks:", networks, "\n")
    while 1:
        for network in networks:
            order = {}
            # EOS specific parameters
            if network == "eos":
                nil = NIL_EOS
                get_balance = eos_balance
                transfer = eos_transfer
            # XRP specific parameters
            elif network == "xrp":
                nil = NIL_XRP
                get_balance = xrp_balance
                transfer = xrp_transfer
            # recycle gateway incoming transfers to the outbound account
            for idx, gate in enumerate(GATE[network]):
                if idx:
                    balance = get_balance(gate["public"])
                    if balance > nil:
                        timestamp()
                        line_number()
                        print(it("red", f"{network} RECYCLER"))
                        print(gate["public"], balance, "\n")
                        # finalize the order
                        order["private"] = gate["private"]
                        order["public"] = gate["public"]
                        order["to"] = GATE[network][0]["public"]
                        order["quantity"] = balance - nil
                        # serialize, sign, and broadcast
                        print(transfer(order), "\n")
        time.sleep(60)
def listener_ripple(account_idx=0,
                    amount=None,
                    issuer_action=None,
                    client_id=None,
                    nonce=0):
    """
    for every block from initialized until detected
        check for transaction to the gateway
            issue or reserve uia upon receipt of gateway transfer

    :param int(account_idx) # from gateway_state.py
    :param float(amount)
    :param str(issuer_action) # None in unit test case
    :param str(client_id) #1.2.X
    :return None:
    """
    gateway = GATE["xrp"][account_idx]["public"]
    uia = GATE["uia"]["xrp"]["asset_name"]
    start_ledger_num = get_validated_ledger()
    checked_ledgers = [start_ledger_num]
    timestamp()
    line_number()
    print(f"nonce {nonce}", "Start ledger:", start_ledger_num, "\n")
    start = time.time()
    while 1:
        elapsed = time.time() - start
        if elapsed > DEPOSIT_TIMEOUT:
            print(f"nonce {nonce}", it("red", "XRP GATEWAY TIMEOUT"), gateway)
            # after timeout, release the address
            if issuer_action == "issue":
                unlock_address("ripple", account_idx, DEPOSIT_PAUSE)
            break
        # get the latest validated ledger number
        current_ledger = get_validated_ledger()
        # get the latest ledger number we checked
        max_checked_ledger = max(checked_ledgers)
        # if there are any new validated ledgers
        if current_ledger > max_checked_ledger + 1:
            # check every ledger from last check till now
            for ledger_num in range(max_checked_ledger + 1, current_ledger):
                print(
                    f"nonce {nonce}",
                    it("green", "Ripple Validated Ledger"),
                    it("yellow", ledger_num),
                    time.ctime()[11:19],
                )
                # get each new validated ledger
                transactions = get_ledger(ledger_num)
                # iterate through all transactions in the list of transactions
                for trx in transactions:
                    if not isinstance(trx["Amount"], dict):
                        # localize data from the transaction
                        amount = int(
                            trx["Amount"]) / 10**6  # convert drops to xrp
                        trx_from = trx["Account"]
                        trx_to = trx["Destination"]
                        # during unit testing
                        if issuer_action is None:
                            print(f"nonce {nonce}", ledger_num, trx, "\n")
                        # determine if it is a transfer to or from the gateway
                        if gateway in [trx_from, trx_to]:
                            timestamp()
                            line_number()
                            # establish gateway transfer direction
                            direction = "INCOMING"
                            if gateway == trx_from:
                                direction = "OUTGOING"
                            print(
                                f"nonce {nonce}",
                                it(
                                    "red",
                                    f"{direction} XRP GATEWAY TRANSFER DETECTED\n",
                                ),
                                f"amount {amount}\n",
                                f"from {trx_from}\n",
                                f"to {trx_to}\n",
                            )
                            # the client_id was assigned deposit gateway address
                            # issue UIA to client_id upon receipt of their foreign funds
                            if issuer_action == "issue" and trx_to == gateway:
                                print(
                                    f"nonce {nonce}",
                                    it(
                                        "red",
                                        f"ISSUING {amount} {uia} to {client_id}\n",
                                    ),
                                )
                                issue("xrp", amount, client_id)
                                # in subprocess unlock the deposit address after wait
                                delay = DEPOSIT_TIMEOUT - elapsed + DEPOSIT_PAUSE
                                unlock_address("xrp", account_idx, delay)
                                return  # but immediately kill the listener
                            # the parent process will soon send foreign funds to client_id
                            # reserve UIA upon hearing proof of this transfer
                            if issuer_action == "reserve" and trx_from == gateway:
                                print(
                                    f"nonce {nonce}",
                                    it("red", f"RESERVING {amount} {uia}\n"),
                                )
                                reserve("xrp", amount)
                                return  # kill the listener
                # append this ledger number to the list of checked numbers
                if ledger_num not in checked_ledgers:
                    checked_ledgers.append(ledger_num)
示例#6
0
    def on_get(self, req, resp):
        """
        When there is a get request made to the deposit server api
        User GET request includes the client_id's BitShares account_name
        Select a gateway wallet from list currently available; remove it from the list
        the available address list will be stored in a json_ipc text pipe
        Server RESPONSE is deposit address and timeout
        After timeout or deposit return address to text pipe list
        """
        confirm_time = {
            "eos": 30,
            "xrp": 2,
        }
        # create a millesecond nonce to log this event
        nonce = milleseconds()
        # extract the incoming parameters to a dictionary
        data = dict(req.params)
        timestamp()
        line_number()
        print(it("red", "DEPOSIT SERVER RECEIVED A GET REQUEST"), "\n")
        call(["hostname", "-I"])
        print(data, "\n")
        client_id = data["client_id"]
        uia = data["uia_name"]
        # translate the incoming uia request to the appropriate network
        network = ""
        if uia == GATE["uia"]["xrp"]["asset_name"]:
            network = "xrp"
        elif uia == GATE["uia"]["eos"]["asset_name"]:
            network = "eos"
        print("network", network, "\n")
        if network in ["xrp", "eos"]:
            # lock an address until this transaction is complete
            gateway_idx = lock_address(network)
            print("gateway index", gateway_idx, "\n")
            if gateway_idx is not None:
                timestamp()
                line_number()
                deposit_address = GATE[network][gateway_idx]["public"]
                print("gateway address", deposit_address, "\n")
                # format a response json
                msg = json_dumps({
                    "response":
                    "success",
                    "server_time":
                    nonce,
                    "deposit_address":
                    deposit_address,
                    "gateway_timeout":
                    "30 MINUTES",
                    "msg":
                    (f"Welcome {client_id}, please deposit your gateway issued "
                     +
                     f"{network} asset, to the {uia} gateway 'deposit_address' "
                     +
                     "in this response.  Make ONE transfer to this address, " +
                     "within the gateway_timeout specified. Transactions on " +
                     f"this network take about {confirm_time[network]} " +
                     "minutes to confirm."),
                })
                print(
                    it("red",
                       f"STARTING {network} LISTENER TO ISSUE to {client_id}"),
                    "\n",
                )
                # dispatch the appropriate listener protocol
                listen = {"eos": listener_eosio, "xrp": listener_ripple}
                # in subprocess listen for payment from client_id to gateway[idx]
                # upon receipt issue asset, else timeout
                listener = Process(
                    target=listen[network],
                    args=(gateway_idx, None, "issue", client_id, nonce),
                )
                listener.start()
                print(f"{network}listener started", "\n")

            else:
                msg = json_dumps({
                    "response":
                    "error",
                    "server_time":
                    nonce,
                    "msg":
                    f"all {uia} gateway addresses are in use, " +
                    "please try again later",
                })

        else:
            msg = json_dumps({
                "response":
                "error",
                "server_time":
                nonce,
                "msg":
                f"{uia} is an invalid gateway UIA, please try again",
            })
        # log the response and build the response body with a data dictionary
        doc = str(nonce) + "_" + uia + "_" + client_id + ".txt"
        json_ipc(doc=doc, text=msg)
        time.sleep(
            5)  # allow some time for listener to start before offering address
        print(msg, "\n")
        resp.body = msg
        resp.status = HTTP_200
示例#7
0
def listener_eosio(
    account_idx=0, amount=None, issuer_action=None, client_id=None, nonce=0
):
    """
    for every block from initialized until detected
        check for transaction to the gateway
            issue or reserve uia upon receipt of gateway transfer

    :param int(account_idx) # from gateway_state.py
    :param float(amount)
    :param str(issuer_action) # None in unit test case
    :param str(client_id) #1.2.X
    :return None:
    """
    gateway = GATE["eos"][account_idx]["public"]
    uia = GATE["uia"]["eos"]["asset_name"]
    start_block_num = get_irreversible_block()
    checked_blocks = [start_block_num]
    print("Start Block:", start_block_num, "\n")
    # block["transactions"][0]["trx"]["transaction"]["actions"][0] holds:
    #   ["name"] # str("transfer") etc.
    #   ["data"] # dict.keys() [to, from, quantity]
    start = time.time()
    while 1:
        elapsed = time.time() - start
        if elapsed > DEPOSIT_TIMEOUT:
            print(
                f"nonce {nonce}",
                it("red", f"{nonce} EOS GATEWAY TIMEOUT"),
                gateway,
                "\n",
            )
            # 10 minutes after timeout, release the address
            if issuer_action == "issue":
                unlock_address("eos", account_idx, DEPOSIT_PAUSE)
            break
        # get the latest irreversible block number
        current_block = get_irreversible_block()
        # get the latest block number we checked
        max_checked_block = max(checked_blocks)
        # if there are any new irreversible blocks
        if current_block > max_checked_block + 1:
            new_blocks = range(max_checked_block + 1, current_block)
            # eosio has a 0.5 second block time, to prevail over network latency:
            # *concurrently* fetch all new blocks
            block_processes = {}  # dictionary of multiprocessing "Process" events
            blocks_pipe = {}  # dictionary of multiprocessing "Value" pipes
            # spawn multpiple processes to gather the "new" blocks
            for block_num in new_blocks:
                manager = Manager()
                blocks_pipe[block_num] = manager.Value(c_wchar_p, "")
                block_processes[block_num] = Process(
                    target=get_block, args=(block_num, blocks_pipe,)
                )
                block_processes[block_num].start()
            # join all subprocess back to main process; wait for all to finish
            for block_num in new_blocks:
                block_processes[block_num].join()
            # extract the blocks from each "Value" in blocks_pipe
            blocks = {}
            for block_num, block in blocks_pipe.items():
                # create block number keyed dict of block data dicts
                blocks[block_num] = block.value
            # with new cache of blocks, check every block from last check till now
            for block_num in new_blocks:
                print(
                    f"nonce {nonce}",
                    it("purple", "Eosio Irreversible Block"),
                    it("yellow", block_num),
                    time.ctime()[11:19],
                    it("purple", int(time.time())),
                    "\n",
                )
                # get each new irreversible block
                block = blocks[block_num]
                transactions = []
                try:
                    transactions = block["transactions"]
                except Exception:
                    pass
                # iterate through all transactions in the list of transactions
                for trx in transactions:
                    actions = []
                    try:
                        actions = trx["trx"]["transaction"]["actions"]
                    except Exception:
                        pass
                    # if there are any, iterate through the actions
                    for action in actions:
                        try:
                            # sort by tranfer ops
                            if (
                                action["name"] == "transfer"
                                # SECURITY: ensure it is the correct contract!!!
                                and action["account"] == "eosio.token"
                            ):
                                # extract transfer op data
                                qty = action["data"]["quantity"]
                                trx_to = action["data"]["to"]
                                trx_from = action["data"]["from"]
                                trx_asset = qty.split(" ")[1].upper()
                                trx_amount = float(qty.split(" ")[0])
                                # sort again by > nil amount of eos
                                if trx_amount > 0.0001 and trx_asset == "EOS":
                                    # during unit testing
                                    # if issuer_action is None:
                                    if DEV:
                                        print(f"nonce {nonce}", block_num, action, "\n")
                                    # if there are any transfers listed
                                    if gateway in [trx_from, trx_to]:
                                        timestamp()
                                        line_number()
                                        print(
                                            f"nonce {nonce}",
                                            it("red", "GATEWAY TRANSFER DETECTED\n"),
                                            f"amount {trx_amount} {trx_asset}\n",
                                            f"from {trx_from}\n",
                                            f"to {trx_to}\n",
                                        )

                                        # issue UIA to client_id
                                        # upon receipt of their foreign funds
                                        if (
                                            issuer_action == "issue"
                                            and trx_to == gateway
                                        ):
                                            print(
                                                f"nonce {nonce}",
                                                it(
                                                    "red",
                                                    f"ISSUING {trx_amount} {uia} to "
                                                    + f"{client_id}\n",
                                                ),
                                            )
                                            issue("eos", trx_amount, client_id)
                                            # unlock the deposit address after some time
                                            delay = (
                                                DEPOSIT_TIMEOUT
                                                - elapsed
                                                + DEPOSIT_PAUSE
                                            )
                                            unlock_address("eos", account_idx, delay)
                                            return
                                        # when returning foreign funds to client,
                                        # upon receipt, reserve equal in UIA
                                        if (
                                            issuer_action == "reserve"
                                            and trx_from == gateway
                                            and trx_amount == amount
                                        ):
                                            print(
                                                f"nonce {nonce}",
                                                it(
                                                    "red", f"RESERVING {amount} {uia}\n"
                                                ),
                                            )
                                            reserve("eos", trx_amount)
                                            return
                        except Exception:
                            print(f"nonce {nonce}", "action", action, "\n")
                            print(traceback.format_exc(), "\n")

                if block_num not in checked_blocks:
                    checked_blocks.append(block_num)
示例#8
0
def withdraw(op):
    """
    in production print_op is replaced with withdraw

        The user has returned some UIA to the issuer!

    upon hearing an on chain UIA transfer to the gateway with memo
    from this definition we trigger a gateway withdrawal event
    release the user's foreign chain funds to the memo
    and burn the returned UIA upon irreversible receipt
    """
    # if its a transfer to gateway with a memo
    tgm = False
    if op[0] == 0:  # transfer
        if op[1]["to"] in [
                GATE["uia"]["eos"]["issuer_id"],
                GATE["uia"]["xrp"]["issuer_id"],
        ]:
            print(it("yellow", "gate uia transfer"))
            if "memo" in op[1].keys():
                print(
                    it("red", "TRANSFER TO GATEWAY WITH MEMO\n\n"),
                    it("yellow", op),
                    "\n",
                )
                tgm = True
            else:
                print(it("red", "WARN: transfer to gateway WITHOUT memo"))
    if tgm:
        timestamp()
        line_number()
        order = {}
        # extract the asset_id of the transfer
        uia_id = op[1]["amount"]["asset_id"]
        print("uia_id", uia_id, "\n")
        # EOS specific parameters
        if uia_id == GATE["uia"]["eos"]["asset_id"]:
            network = "eos"
            verify = verify_eosio_account
            listen = listener_eosio
            transfer = eos_transfer
            # eos transfers require a url
            order["url"] = eosio_nodes()[
                0]  # FIXME what happens if node fails?
        # XRP specific parameters
        elif uia_id == GATE["uia"]["xrp"]["asset_id"]:
            network = "xrp"
            verify = verify_ripple_account
            listen = listener_ripple
            transfer = xrp_transfer
        memo = op[1][
            "memo"]  # dict with keys("from", "to", "nonce", "message")
        order["private"] = GATE[network][0]["private"]
        order["public"] = GATE[network][0]["public"]
        # convert graphene operation amount to human readable
        order["quantity"] = (op[1]["amount"]["amount"] /
                             10**GATE["uia"][network]["asset_precision"])
        # decode the client's memo using the issuers private key
        order["to"] = ovaltine(memo, GATE["uia"][network]["issuer_private"])
        print(f"decoded {network} client", order["to"], "\n")
        # confirm we're dealing with a legit client address
        if verify(order["to"]):
            listener = Process(
                target=listen,
                args=(
                    0,
                    order["quantity"],
                    "reserve",  # issuer_action
                    None,  # # always None for reserve
                ),
            )  # upon hearing real foreign chain transfer, reserve the uia equal
            listener.start()
            print(
                it(
                    "red",
                    f"STARTING {network} LISTENER TO RESERVE {order['quantity']}\n",
                ))
            # wait for listener subprocess to warm up then transfer the order
            time.sleep(30)
            timestamp()
            line_number()
            print(transfer(order))
        else:
            print(
                it("red",
                   f"WARN: memo is NOT a valid {network} account name\n"))