Android Open Source - neoscoin-wallet Payment Protocol






From Project

Back to project page neoscoin-wallet.

License

The source code is released under:

GNU General Public License

If you think the Android project neoscoin-wallet listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

/*
 * Copyright 2014 the original author or authors.
 *//from   w w w  . j a v  a  2 s .  co  m
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package de.schildbach.wallet.util;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;

import com.google.bitcoin.core.CoinDefinition;
import org.bitcoin.protocols.payments.Protos;

import com.google.bitcoin.core.Address;
import com.google.bitcoin.core.ScriptException;
import com.google.bitcoin.core.Transaction;
import com.google.bitcoin.protocols.payments.PaymentRequestException;
import com.google.bitcoin.protocols.payments.PaymentSession;
import com.google.bitcoin.protocols.payments.PaymentSession.PkiVerificationData;
import com.google.bitcoin.script.Script;
import com.google.bitcoin.script.ScriptBuilder;
import com.google.protobuf.ByteString;
import com.google.protobuf.InvalidProtocolBufferException;
import com.google.protobuf.UninitializedMessageException;

import de.schildbach.wallet.Constants;
import de.schildbach.wallet.PaymentIntent;

/**
 * @author Andreas Schildbach
 */
public final class PaymentProtocol
{
  public static final String MIMETYPE_PAYMENTREQUEST = "application/"+ CoinDefinition.coinName.toLowerCase()+"-paymentrequest"; // BIP 71
  public static final String MIMETYPE_PAYMENT = "application/"+ CoinDefinition.coinName.toLowerCase()+"-payment"; // BIP 71
  public static final String MIMETYPE_PAYMENTACK = "application/"+ CoinDefinition.coinName.toLowerCase()+"-paymentack"; // BIP 71

  public static Protos.PaymentRequest createPaymentRequest(final BigInteger amount, @Nonnull final Address toAddress, final String memo,
      final String paymentUrl)
  {
    if (amount != null && amount.compareTo(BigInteger.valueOf(Long.MAX_VALUE)) > 0)
      throw new IllegalArgumentException("amount too big for protobuf: " + amount);

    final Protos.Output.Builder output = Protos.Output.newBuilder();
    output.setAmount(amount != null ? amount.longValue() : 0);
    output.setScript(ByteString.copyFrom(ScriptBuilder.createOutputScript(toAddress).getProgram()));

    final Protos.PaymentDetails.Builder paymentDetails = Protos.PaymentDetails.newBuilder();
    paymentDetails.setNetwork(Constants.NETWORK_PARAMETERS.getPaymentProtocolId());
    paymentDetails.addOutputs(output);
    if (memo != null)
      paymentDetails.setMemo(memo);
    if (paymentUrl != null)
      paymentDetails.setPaymentUrl(paymentUrl);
    paymentDetails.setTime(System.currentTimeMillis());

    final Protos.PaymentRequest.Builder paymentRequest = Protos.PaymentRequest.newBuilder();
    paymentRequest.setSerializedPaymentDetails(paymentDetails.build().toByteString());

    return paymentRequest.build();
  }

  public static PaymentIntent parsePaymentRequest(@Nonnull final byte[] serializedPaymentRequest) throws PaymentRequestException
  {
    try
    {
      if (serializedPaymentRequest.length > 50000)
        throw new PaymentRequestException("payment request too big: " + serializedPaymentRequest.length);

      final Protos.PaymentRequest paymentRequest = Protos.PaymentRequest.parseFrom(serializedPaymentRequest);

      final String pkiName;
      final String pkiOrgName;
      final String pkiCaName;
      if (!"none".equals(paymentRequest.getPkiType()))
      {
        // implicitly verify PKI signature
        final PkiVerificationData verificationData = new PaymentSession(paymentRequest, true).pkiVerificationData;
        pkiName = verificationData.name;
        pkiOrgName = verificationData.orgName;
        pkiCaName = verificationData.rootAuthorityName;
      }
      else
      {
        pkiName = null;
        pkiOrgName = null;
        pkiCaName = null;
      }

      if (paymentRequest.getPaymentDetailsVersion() != 1)
        throw new PaymentRequestException.InvalidVersion("cannot handle payment details version: "
            + paymentRequest.getPaymentDetailsVersion());

      final Protos.PaymentDetails paymentDetails = Protos.PaymentDetails.newBuilder().mergeFrom(paymentRequest.getSerializedPaymentDetails())
          .build();

      final long currentTimeSecs = System.currentTimeMillis() / 1000;
      if (paymentDetails.hasExpires() && currentTimeSecs >= paymentDetails.getExpires())
        throw new PaymentRequestException.Expired("payment details expired: current time " + currentTimeSecs + " after expiry time "
            + paymentDetails.getExpires());

      if (!paymentDetails.getNetwork().equals(Constants.NETWORK_PARAMETERS.getPaymentProtocolId()))
        throw new PaymentRequestException.InvalidNetwork("cannot handle payment request network: " + paymentDetails.getNetwork());

      final ArrayList<PaymentIntent.Output> outputs = new ArrayList<PaymentIntent.Output>(paymentDetails.getOutputsCount());
      for (final Protos.Output output : paymentDetails.getOutputsList())
        outputs.add(parseOutput(output));

      final String memo = paymentDetails.hasMemo() ? paymentDetails.getMemo() : null;
      final String paymentUrl = paymentDetails.hasPaymentUrl() ? paymentDetails.getPaymentUrl() : null;
      final byte[] merchantData = paymentDetails.hasMerchantData() ? paymentDetails.getMerchantData().toByteArray() : null;

      final PaymentIntent paymentIntent = new PaymentIntent(PaymentIntent.Standard.BIP70, pkiName, pkiOrgName, pkiCaName,
          outputs.toArray(new PaymentIntent.Output[0]), memo, paymentUrl, merchantData, null);

      if (paymentIntent.hasPaymentUrl() && !paymentIntent.isSupportedPaymentUrl())
        throw new PaymentRequestException.InvalidPaymentURL("cannot handle payment url: " + paymentIntent.paymentUrl);

      return paymentIntent;
    }
    catch (final InvalidProtocolBufferException x)
    {
      throw new PaymentRequestException(x);
    }
    catch (final UninitializedMessageException x)
    {
      throw new PaymentRequestException(x);
    }
  }

  private static PaymentIntent.Output parseOutput(@Nonnull final Protos.Output output) throws PaymentRequestException.InvalidOutputs
  {
    try
    {
      final BigInteger amount = BigInteger.valueOf(output.getAmount());
      final Script script = new Script(output.getScript().toByteArray());
      return new PaymentIntent.Output(amount, script);
    }
    catch (final ScriptException x)
    {
      throw new PaymentRequestException.InvalidOutputs("unparseable script in output: " + output.toString());
    }
  }

  public static Protos.Payment createPaymentMessage(@Nonnull final Transaction transaction, @Nullable final Address refundAddress,
      @Nullable final BigInteger refundAmount, @Nullable final String memo, @Nullable final byte[] merchantData)
  {
    final Protos.Payment.Builder builder = Protos.Payment.newBuilder();

    builder.addTransactions(ByteString.copyFrom(transaction.unsafeBitcoinSerialize()));

    if (refundAddress != null)
    {
      if (refundAmount.compareTo(BigInteger.valueOf(Long.MAX_VALUE)) > 0)
        throw new IllegalArgumentException("refund amount too big for protobuf: " + refundAmount);

      final Protos.Output.Builder refundOutput = Protos.Output.newBuilder();
      refundOutput.setAmount(refundAmount.longValue());
      refundOutput.setScript(ByteString.copyFrom(ScriptBuilder.createOutputScript(refundAddress).getProgram()));
      builder.addRefundTo(refundOutput);
    }

    if (memo != null)
      builder.setMemo(memo);

    if (merchantData != null)
      builder.setMerchantData(ByteString.copyFrom(merchantData));

    return builder.build();
  }

  public static List<Transaction> parsePaymentMessage(final Protos.Payment paymentMessage)
  {
    final List<Transaction> transactions = new ArrayList<Transaction>(paymentMessage.getTransactionsCount());

    for (final ByteString transaction : paymentMessage.getTransactionsList())
      transactions.add(new Transaction(Constants.NETWORK_PARAMETERS, transaction.toByteArray()));

    return transactions;
  }

  public static Protos.PaymentACK createPaymentAck(@Nonnull final Protos.Payment paymentMessage, @Nullable final String memo)
  {
    final Protos.PaymentACK.Builder builder = Protos.PaymentACK.newBuilder();

    builder.setPayment(paymentMessage);

    builder.setMemo(memo);

    return builder.build();
  }

  public static String parsePaymentAck(@Nonnull final Protos.PaymentACK paymentAck)
  {
    final String memo = paymentAck.hasMemo() ? paymentAck.getMemo() : null;

    return memo;
  }
}




Java Source Code List

de.schildbach.wallet.AddressBookProvider.java
de.schildbach.wallet.Configuration.java
de.schildbach.wallet.Constants.java
de.schildbach.wallet.ExchangeRatesProvider.java
de.schildbach.wallet.PaymentIntent.java
de.schildbach.wallet.WalletApplication.java
de.schildbach.wallet.WalletBalanceWidgetProvider.java
de.schildbach.wallet.camera.CameraManager.java
de.schildbach.wallet.integration.android.BitcoinIntegration.java
de.schildbach.wallet.integration.sample.SampleActivity.java
de.schildbach.wallet.offline.AcceptBluetoothService.java
de.schildbach.wallet.offline.AcceptBluetoothThread.java
de.schildbach.wallet.offline.DirectPaymentTask.java
de.schildbach.wallet.service.AutosyncReceiver.java
de.schildbach.wallet.service.BlockchainServiceImpl.java
de.schildbach.wallet.service.BlockchainService.java
de.schildbach.wallet.ui.AboutActivity.java
de.schildbach.wallet.ui.AbstractBindServiceActivity.java
de.schildbach.wallet.ui.AbstractOnDemandServiceActivity.java
de.schildbach.wallet.ui.AbstractWalletActivity.java
de.schildbach.wallet.ui.AddressAndLabel.java
de.schildbach.wallet.ui.AddressBookActivity.java
de.schildbach.wallet.ui.BlockListFragment.java
de.schildbach.wallet.ui.CurrencyAmountView.java
de.schildbach.wallet.ui.CurrencyCalculatorLink.java
de.schildbach.wallet.ui.CurrencySymbolDrawable.java
de.schildbach.wallet.ui.CurrencyTextView.java
de.schildbach.wallet.ui.DialogBuilder.java
de.schildbach.wallet.ui.EditAddressBookEntryFragment.java
de.schildbach.wallet.ui.ExchangeRateLoader.java
de.schildbach.wallet.ui.ExchangeRatesActivity.java
de.schildbach.wallet.ui.ExchangeRatesFragment.java
de.schildbach.wallet.ui.FileAdapter.java
de.schildbach.wallet.ui.HelpDialogFragment.java
de.schildbach.wallet.ui.ImportDialogButtonEnablerListener.java
de.schildbach.wallet.ui.ImportKeysActivity.java
de.schildbach.wallet.ui.InputParser.java
de.schildbach.wallet.ui.NetworkMonitorActivity.java
de.schildbach.wallet.ui.PeerListFragment.java
de.schildbach.wallet.ui.PreferencesActivity.java
de.schildbach.wallet.ui.ProgressDialogFragment.java
de.schildbach.wallet.ui.ReportIssueDialogBuilder.java
de.schildbach.wallet.ui.RequestCoinsActivity.java
de.schildbach.wallet.ui.RequestCoinsFragment.java
de.schildbach.wallet.ui.RequestPaymentRequestTask.java
de.schildbach.wallet.ui.ScanActivity.java
de.schildbach.wallet.ui.ScannerView.java
de.schildbach.wallet.ui.SendCoinsActivity.java
de.schildbach.wallet.ui.SendCoinsFragment.java
de.schildbach.wallet.ui.SendCoinsOfflineTask.java
de.schildbach.wallet.ui.SendCoinsQrActivity.java
de.schildbach.wallet.ui.SendingAddressesFragment.java
de.schildbach.wallet.ui.ShowPasswordCheckListener.java
de.schildbach.wallet.ui.TransactionActivity.java
de.schildbach.wallet.ui.TransactionFragment.java
de.schildbach.wallet.ui.TransactionsListAdapter.java
de.schildbach.wallet.ui.TransactionsListFragment.java
de.schildbach.wallet.ui.WalletActionsFragment.java
de.schildbach.wallet.ui.WalletActivity.java
de.schildbach.wallet.ui.WalletAddressFragment.java
de.schildbach.wallet.ui.WalletAddressesAdapter.java
de.schildbach.wallet.ui.WalletAddressesFragment.java
de.schildbach.wallet.ui.WalletBalanceFragment.java
de.schildbach.wallet.ui.WalletBalanceLoader.java
de.schildbach.wallet.ui.WalletDisclaimerFragment.java
de.schildbach.wallet.ui.WalletTransactionsFragment.java
de.schildbach.wallet.util.AbstractClipboardManager.java
de.schildbach.wallet.util.Base43.java
de.schildbach.wallet.util.BitmapFragment.java
de.schildbach.wallet.util.Bluetooth.java
de.schildbach.wallet.util.CircularProgressView.java
de.schildbach.wallet.util.CrashReporter.java
de.schildbach.wallet.util.Crypto.java
de.schildbach.wallet.util.GenericUtils.java
de.schildbach.wallet.util.HttpGetThread.java
de.schildbach.wallet.util.Io.java
de.schildbach.wallet.util.Iso8601Format.java
de.schildbach.wallet.util.LinuxSecureRandom.java
de.schildbach.wallet.util.Nfc.java
de.schildbach.wallet.util.PaymentProtocol.java
de.schildbach.wallet.util.Qr.java
de.schildbach.wallet.util.ThrottlingWalletChangeListener.java
de.schildbach.wallet.util.ViewPagerTabs.java
de.schildbach.wallet.util.WalletUtils.java