CounterpartyXCP / counterparty-core

Counterparty Protocol Reference Implementation
http://counterparty.io
MIT License
287 stars 205 forks source link

Address Options API Route #2640

Open droplister opened 3 hours ago

droplister commented 3 hours ago

I know that address options are not used much, and possibly some of the new features won't respect the flag, but there's no way via the API to check an address' options and maybe that would be worth having?

While this isn't a popular option, it's designed for a CEX to be able to support Counterparty deposits easily by lowering the support and wallet management overhead for an exchange interested in supporting XCP.

A route like one of these:

         "/v2/addresses/<address>": queries.get_address,
        "/v2/addresses/<address>/options": queries.get_address,

And a query like this one:

def get_address(db, address: str):
    """
    Returns the options of an address
    :param str address: The address to return (e.g. $ADDRESS_1)
    """
    return select_rows(
        db,
        "addresses",
        where=[
            {"address": address},
        ]
    )
adamkrellenstein commented 3 hours ago

sorry I don't know what "options" means in this case!

droplister commented 3 hours ago

If you broadcast "options n" where n is the options flag you want to set, then the options field on addresses is updated.

There is only one option:

ADDRESS_OPTION_REQUIRE_MEMO = 1
ADDRESS_OPTION_MAX_VALUE = ADDRESS_OPTION_REQUIRE_MEMO  # Or list of all the address options

What's nice about it is that if you flag your address this way, if someone sends you an asset without a memo the send fails. So, in theory, an exchange could give someone a random string when they want to make a deposit and tell them to put it in the memo field. This way they have to manage a single deposit address while knowing which internal accounts have claims on the balances. Someone could put an invalid string, but it makes the wallet management and support issues likely much less.


def parse_options_from_string(string):
    """Parse options integer from string, if exists."""
    string_list = string.split(" ")
    if len(string_list) == 2:
        try:
            options = int(string_list.pop())
        except:  # noqa: E722
            raise exceptions.OptionsError("options not an integer")  # noqa: B904
        return options
    else:
        return False

def validate_address_options(options):
    """Ensure the options are all valid and in range."""
    if (options > config.MAX_INT) or (options < 0):
        raise exceptions.OptionsError("options integer overflow")
    elif options > config.ADDRESS_OPTION_MAX_VALUE:
        raise exceptions.OptionsError("options out of range")
    elif not active_options(config.ADDRESS_OPTION_MAX_VALUE, options):
        raise exceptions.OptionsError("options not possible")

def active_options(config, options):
    """Checks if options active in some given config."""
    return config & options == options
def validate(db, source, timestamp, value, fee_fraction_int, text, block_index):

    if util.enabled("options_require_memo") and text and text.lower().startswith("options"):
        try:
            # Check for options and if they are valid.
            options = util.parse_options_from_string(text)
            if options is not False:
                util.validate_address_options(options)
        except exceptions.OptionsError as e:
            problems.append(str(e))

    return problems

    # Options? Should not fail to parse due to above checks.
    if util.enabled("options_require_memo") and text and text.lower().startswith("options"):
        options = util.parse_options_from_string(text)
        if options is not False:
            op_bindings = {
                "block_index": tx["block_index"],
                "address": tx["source"],
                "options": options,
            }
            existing_address = ledger.get_addresses(db, address=tx["source"])
            if len(existing_address) == 0:
                ledger.insert_record(db, "addresses", op_bindings, "NEW_ADDRESS_OPTIONS")
            else:
                ledger.insert_update(
                    db, "addresses", "address", tx["source"], op_bindings, "ADDRESS_OPTIONS_UPDATE"
                )