예제 #1
0
  /**
   * Simple Bitcoin URI builder using known good fields.
   *
   * @param params The network parameters that determine which network the URI is for.
   * @param address The Bitcoin address
   * @param amount The amount
   * @param label A label
   * @param message A message
   * @return A String containing the Bitcoin URI
   */
  public static String convertToBitcoinURI(
      NetworkParameters params,
      String address,
      @Nullable Coin amount,
      @Nullable String label,
      @Nullable String message) {
    checkNotNull(params);
    checkNotNull(address);
    if (amount != null && amount.signum() < 0) {
      throw new IllegalArgumentException("Coin must be positive");
    }

    StringBuilder builder = new StringBuilder();
    String scheme = params.getUriScheme();
    builder.append(scheme).append(":").append(address);

    boolean questionMarkHasBeenOutput = false;

    if (amount != null) {
      builder.append(QUESTION_MARK_SEPARATOR).append(FIELD_AMOUNT).append("=");
      builder.append(amount.toPlainString());
      questionMarkHasBeenOutput = true;
    }

    if (label != null && !"".equals(label)) {
      if (questionMarkHasBeenOutput) {
        builder.append(AMPERSAND_SEPARATOR);
      } else {
        builder.append(QUESTION_MARK_SEPARATOR);
        questionMarkHasBeenOutput = true;
      }
      builder.append(FIELD_LABEL).append("=").append(encodeURLString(label));
    }

    if (message != null && !"".equals(message)) {
      if (questionMarkHasBeenOutput) {
        builder.append(AMPERSAND_SEPARATOR);
      } else {
        builder.append(QUESTION_MARK_SEPARATOR);
      }
      builder.append(FIELD_MESSAGE).append("=").append(encodeURLString(message));
    }

    return builder.toString();
  }
예제 #2
0
  /**
   * Constructs a new object by trying to parse the input as a valid Bitcoin URI.
   *
   * @param params The network parameters that determine which network the URI is from, or null if
   *     you don't have any expectation about what network the URI is for and wish to check
   *     yourself.
   * @param input The raw URI data to be parsed (see class comments for accepted formats)
   * @throws BitcoinURIParseException If the input fails Bitcoin URI syntax and semantic checks.
   */
  public BitcoinURI(@Nullable NetworkParameters params, String input)
      throws BitcoinURIParseException {
    checkNotNull(input);

    String scheme =
        null == params ? AbstractBitcoinNetParams.BITCOIN_SCHEME : params.getUriScheme();

    // Attempt to form the URI (fail fast syntax checking to official standards).
    URI uri;
    try {
      uri = new URI(input);
    } catch (URISyntaxException e) {
      throw new BitcoinURIParseException("Bad URI syntax", e);
    }

    // URI is formed as  bitcoin:<address>?<query parameters>
    // blockchain.info generates URIs of non-BIP compliant form bitcoin://address?....
    // We support both until Ben fixes his code.

    // Remove the bitcoin scheme.
    // (Note: getSchemeSpecificPart() is not used as it unescapes the label and parse then fails.
    // For instance with :
    // bitcoin:129mVqKUmJ9uwPxKJBnNdABbuaaNfho4Ha?amount=0.06&label=Tom%20%26%20Jerry
    // the & (%26) in Tom and Jerry gets interpreted as a separator and the label then gets parsed
    // as 'Tom ' instead of 'Tom & Jerry')
    String blockchainInfoScheme = scheme + "://";
    String correctScheme = scheme + ":";
    String schemeSpecificPart;
    if (input.startsWith(blockchainInfoScheme)) {
      schemeSpecificPart = input.substring(blockchainInfoScheme.length());
    } else if (input.startsWith(correctScheme)) {
      schemeSpecificPart = input.substring(correctScheme.length());
    } else {
      throw new BitcoinURIParseException("Unsupported URI scheme: " + uri.getScheme());
    }

    // Split off the address from the rest of the query parameters.
    String[] addressSplitTokens = schemeSpecificPart.split("\\?", 2);
    if (addressSplitTokens.length == 0)
      throw new BitcoinURIParseException("No data found after the bitcoin: prefix");
    String addressToken = addressSplitTokens[0]; // may be empty!

    String[] nameValuePairTokens;
    if (addressSplitTokens.length == 1) {
      // Only an address is specified - use an empty '<name>=<value>' token array.
      nameValuePairTokens = new String[] {};
    } else {
      // Split into '<name>=<value>' tokens.
      nameValuePairTokens = addressSplitTokens[1].split("&");
    }

    // Attempt to parse the rest of the URI parameters.
    parseParameters(params, addressToken, nameValuePairTokens);

    if (!addressToken.isEmpty()) {
      // Attempt to parse the addressToken as a Bitcoin address for this network
      try {
        Address address = Address.fromBase58(params, addressToken);
        putWithValidation(FIELD_ADDRESS, address);
      } catch (final AddressFormatException e) {
        throw new BitcoinURIParseException("Bad address", e);
      }
    }

    if (addressToken.isEmpty() && getPaymentRequestUrl() == null) {
      throw new BitcoinURIParseException("No address and no r= parameter found");
    }
  }