Bug 1318990 - PaymentRequestUpdateEvent interface and PaymentRequest API onshippingaddress/optionchange implementation. r=baku
authorEden Chuang <echuang@mozilla.com>
Fri, 23 Jun 2017 17:15:51 +0800
changeset 417124 acd8a6411e8d2fbb93993f713079c778e2b90f9d
parent 417123 ffefe7f1771d63cf3fb2875f453f8c99c1781a19
child 417125 922502d61ee27d2589b9be86d2667a624b5b726f
push id1517
push userjlorenzo@mozilla.com
push dateThu, 14 Sep 2017 16:50:54 +0000
treeherdermozilla-release@3b41fd564418 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbaku
bugs1318990
milestone56.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1318990 - PaymentRequestUpdateEvent interface and PaymentRequest API onshippingaddress/optionchange implementation. r=baku
dom/interfaces/payments/moz.build
dom/interfaces/payments/nsIPaymentActionRequest.idl
dom/interfaces/payments/nsIPaymentAddress.idl
dom/interfaces/payments/nsIPaymentRequestService.idl
dom/interfaces/payments/nsIPaymentUIService.idl
dom/payments/PaymentActionRequest.cpp
dom/payments/PaymentActionRequest.h
dom/payments/PaymentRequest.cpp
dom/payments/PaymentRequest.h
dom/payments/PaymentRequestData.cpp
dom/payments/PaymentRequestData.h
dom/payments/PaymentRequestManager.cpp
dom/payments/PaymentRequestManager.h
dom/payments/PaymentRequestModule.cpp
dom/payments/PaymentRequestService.cpp
dom/payments/PaymentRequestUpdateEvent.cpp
dom/payments/PaymentRequestUpdateEvent.h
dom/payments/PaymentRequestUtils.cpp
dom/payments/PaymentRequestUtils.h
dom/payments/PaymentResponse.cpp
dom/payments/PaymentResponse.h
dom/payments/ipc/PPaymentRequest.ipdl
dom/payments/ipc/PaymentRequestChild.cpp
dom/payments/ipc/PaymentRequestChild.h
dom/payments/ipc/PaymentRequestParent.cpp
dom/payments/moz.build
dom/webidl/PaymentRequestUpdateEvent.webidl
dom/webidl/moz.build
--- a/dom/interfaces/payments/moz.build
+++ b/dom/interfaces/payments/moz.build
@@ -2,14 +2,15 @@
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 XPIDL_SOURCES += [
     'nsIPaymentActionRequest.idl',
     'nsIPaymentActionResponse.idl',
+    'nsIPaymentAddress.idl',
     'nsIPaymentRequest.idl',
     'nsIPaymentRequestService.idl',
     'nsIPaymentUIService.idl',
 ]
 
 XPIDL_MODULE = 'dom_payments'
--- a/dom/interfaces/payments/nsIPaymentActionRequest.idl
+++ b/dom/interfaces/payments/nsIPaymentActionRequest.idl
@@ -2,34 +2,38 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsISupports.idl"
 #include "nsIVariant.idl"
 #include "nsIPaymentRequest.idl"
 #include "nsIPaymentActionResponse.idl"
+#include "nsIPaymentAddress.idl"
 
 interface nsIArray;
 
 [builtinclass, uuid(3fef5459-b0ea-469b-be9f-b99e8ca75d3d)]
 interface nsIPaymentActionCallback : nsISupports
 {
   void respondPayment(in nsIPaymentActionResponse aResponse);
+  void changeShippingAddress(in AString aRequestId, in nsIPaymentAddress aAddress);
+  void changeShippingOption(in AString aRequestId, in AString aOption);
 };
 
 [builtinclass, uuid(7ddbe8be-beac-4952-96f6-619981dff7a6)]
 interface nsIPaymentActionRequest : nsISupports
 {
   const uint32_t UNKNOWN_ACTION = 0;
   const uint32_t CREATE_ACTION = 1;
   const uint32_t CANMAKE_ACTION = 2;
   const uint32_t SHOW_ACTION = 3;
   const uint32_t ABORT_ACTION = 4;
   const uint32_t COMPLETE_ACTION = 5;
+  const uint32_t UPDATE_ACTION = 6;
 
   /*
    *  The payment request identifier.
    */
   readonly attribute AString requestId;
 
   /*
    *  The type of the requested task.
@@ -94,16 +98,31 @@ interface nsIPaymentCompleteActionReques
   /*
    *  Initialize function for this request.
    */
   void initRequest(in AString aRequestId,
                    in nsIPaymentActionCallback aCallback,
                    in AString aCompleteStatus);
 };
 
+[builtinclass, uuid(21f631e8-c047-4fd8-b3c6-68e26c62639a)]
+interface nsIPaymentUpdateActionRequest : nsIPaymentActionRequest
+{
+  /*
+   *  The details information for updating the specified payment request.
+   */
+  readonly attribute nsIPaymentDetails details;
+
+  /*
+   *  Initialize function for this request.
+   */
+  void initRequest(in AString aRequestId,
+                   in nsIPaymentActionCallback aCallback,
+                   in nsIPaymentDetails aDetails);
+};
 
 %{C++
 #define NS_PAYMENT_ACTION_REQUEST_CID \
   { 0x7ddbe8be, 0xbeac, 0x4952, { 0x96, 0xf6, 0x61, 0x99, 0x81, 0xdf, 0xf7, 0xa6 } }
 #define NS_PAYMENT_ACTION_REQUEST_CONTRACT_ID \
   "@mozilla.org/dom/payments/payment-action-request;1"
 
 #define NS_PAYMENT_CREATE_ACTION_REQUEST_CID \
@@ -111,9 +130,13 @@ interface nsIPaymentCompleteActionReques
 #define NS_PAYMENT_CREATE_ACTION_REQUEST_CONTRACT_ID \
   "@mozilla.org/dom/payments/payment-create-action-request;1"
 
 #define NS_PAYMENT_COMPLETE_ACTION_REQUEST_CID \
   { 0x4429697d, 0x1135, 0x47de, { 0xa4, 0x6e, 0x51, 0x96, 0xd3, 0x99, 0xec, 0x55 } }
 #define NS_PAYMENT_COMPLETE_ACTION_REQUEST_CONTRACT_ID \
   "@mozilla.org/dom/payments/payment-complete-action-request;1"
 
+#define NS_PAYMENT_UPDATE_ACTION_REQUEST_CID \
+  { 0x21f631e8, 0xc047, 0x4fd8, { 0xb3, 0xc6, 0x68, 0xe2, 0x6c, 0x62, 0x63, 0x9a } }
+#define NS_PAYMENT_UPDATE_ACTION_REQUEST_CONTRACT_ID \
+  "@mozilla.org/dom/payments/payment-update-action-request;1"
 %}
new file mode 100644
--- /dev/null
+++ b/dom/interfaces/payments/nsIPaymentAddress.idl
@@ -0,0 +1,43 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsISupports.idl"
+
+interface nsIArray;
+
+[builtinclass, scriptable, uuid(49a02241-7e48-477a-9345-9f246925dcb3)]
+interface nsIPaymentAddress : nsISupports
+{
+  readonly attribute AString country;
+  readonly attribute nsIArray addressLine;
+  readonly attribute AString region;
+  readonly attribute AString city;
+  readonly attribute AString dependentLocality;
+  readonly attribute AString postalCode;
+  readonly attribute AString sortingCode;
+  readonly attribute AString languageCode;
+  readonly attribute AString organization;
+  readonly attribute AString recipient;
+  readonly attribute AString phone;
+
+  void init(in AString aCountry,
+            in nsIArray aAddressLine,
+            in AString aRegion,
+            in AString aCity,
+            in AString aDependentLocality,
+            in AString aPostalCode,
+            in AString aSortingCode,
+            in AString aLanguageCode,
+            in AString aOrganization,
+            in AString aRecipient,
+            in AString aPhone);
+};
+
+%{C++
+#define NS_PAYMENT_ADDRESS_CID \
+  { 0x49a02241, 0x7e48, 0x477a, { 0x93, 0x45, 0x9f, 0x24, 0x69, 0x25, 0xdc, 0xb3 } }
+#define NS_PAYMENT_ADDRESS_CONTRACT_ID \
+  "@mozilla.org/dom/payments/payment-address;1"
+%}
--- a/dom/interfaces/payments/nsIPaymentRequestService.idl
+++ b/dom/interfaces/payments/nsIPaymentRequestService.idl
@@ -3,16 +3,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsISupports.idl"
 #include "nsIVariant.idl"
 #include "nsIPaymentRequest.idl"
 #include "nsIPaymentActionRequest.idl"
 #include "nsIPaymentActionResponse.idl"
+#include "nsIPaymentAddress.idl"
 #include "nsISimpleEnumerator.idl"
 #include "nsIPaymentUIService.idl"
 
 /*
  *  nsPaymentRequestService is used to manage the created PaymentRequest in the
  *  chrome process. It is also the IPC agent for payment UI to communicate with
  *  merchant side.
  */
@@ -35,16 +36,23 @@ interface nsIPaymentRequestService : nsI
    *  from content process.
    */
   void requestPayment(in nsIPaymentActionRequest aRequest);
 
   /*
    *  respondPayment is used for payment UI to respond the asked action result.
    */
   void respondPayment(in nsIPaymentActionResponse aResponse);
+
+  /*
+   *  These methods are used for payment UI to inform merchant the shipping
+   *  address/option change.
+   */
+  void changeShippingAddress(in AString requestId, in nsIPaymentAddress aAddress);
+  void changeShippingOption(in AString requestId, in AString option);
 };
 
 %{C++
 #define NS_PAYMENT_REQUEST_SERVICE_CID \
   { 0xcccd665f, 0xedf3, 0x41fc, { 0xab, 0x9b, 0xfc, 0x55, 0xb3, 0x73, 0x40, 0xaa } }
 #define NS_PAYMENT_REQUEST_SERVICE_CONTRACT_ID \
   "@mozilla.org/dom/payments/payment-request-service;1"
 %}
--- a/dom/interfaces/payments/nsIPaymentUIService.idl
+++ b/dom/interfaces/payments/nsIPaymentUIService.idl
@@ -8,9 +8,10 @@
 
 [scriptable, uuid(ea008d0c-9e9f-411f-a6c5-a62106ba7ab9)]
 interface nsIPaymentUIService : nsISupports
 {
   nsIPaymentActionResponse canMakePayment(in AString requestId);
   nsIPaymentActionResponse showPayment(in AString requestId);
   nsIPaymentActionResponse abortPayment(in AString requestId);
   nsIPaymentActionResponse completePayment(in AString requestId);
+  nsIPaymentActionResponse updatePayment(in AString requestId);
 };
--- a/dom/payments/PaymentActionRequest.cpp
+++ b/dom/payments/PaymentActionRequest.cpp
@@ -158,10 +158,41 @@ PaymentCompleteActionRequest::InitReques
   nsresult rv = Init(aRequestId, nsIPaymentActionRequest::COMPLETE_ACTION, aCallback);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
   mCompleteStatus = aCompleteStatus;
   return NS_OK;
 }
 
+/* PaymentUpdateActionRequest */
+
+NS_IMPL_ISUPPORTS_INHERITED(PaymentUpdateActionRequest,
+                            PaymentActionRequest,
+                            nsIPaymentUpdateActionRequest)
+
+NS_IMETHODIMP
+PaymentUpdateActionRequest::GetDetails(nsIPaymentDetails** aDetails)
+{
+  NS_ENSURE_ARG_POINTER(aDetails);
+  MOZ_ASSERT(mDetails);
+  nsCOMPtr<nsIPaymentDetails> details = mDetails;
+  details.forget(aDetails);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentUpdateActionRequest::InitRequest(const nsAString& aRequestId,
+                                        nsIPaymentActionCallback* aCallback,
+                                        nsIPaymentDetails* aDetails)
+{
+  NS_ENSURE_ARG_POINTER(aCallback);
+  NS_ENSURE_ARG_POINTER(aDetails);
+  nsresult rv = Init(aRequestId, nsIPaymentActionRequest::UPDATE_ACTION, aCallback);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+  mDetails = aDetails;
+  return NS_OK;
+}
+
 } // end of namespace dom
 } // end of namespace mozilla
--- a/dom/payments/PaymentActionRequest.h
+++ b/dom/payments/PaymentActionRequest.h
@@ -61,12 +61,27 @@ public:
   PaymentCompleteActionRequest();
 
 private:
   ~PaymentCompleteActionRequest() = default;
 
   nsString mCompleteStatus;
 };
 
+class PaymentUpdateActionRequest final : public nsIPaymentUpdateActionRequest
+                                       , public PaymentActionRequest
+{
+public:
+  NS_DECL_ISUPPORTS_INHERITED
+  NS_FORWARD_NSIPAYMENTACTIONREQUEST(PaymentActionRequest::)
+  NS_DECL_NSIPAYMENTUPDATEACTIONREQUEST
+
+  PaymentUpdateActionRequest() = default;
+private:
+  ~PaymentUpdateActionRequest() = default;
+
+  nsCOMPtr<nsIPaymentDetails> mDetails;
+};
+
 } // end of namespace dom
 } // end of namespace mozilla
 
 #endif
--- a/dom/payments/PaymentRequest.cpp
+++ b/dom/payments/PaymentRequest.cpp
@@ -147,16 +147,29 @@ PaymentRequest::IsValidDetailsInit(const
                            aDetails.mTotal.mAmount.mValue, aErrorMsg)) {
     return false;
   }
 
   return IsValidDetailsBase(aDetails, aErrorMsg);
 }
 
 bool
+PaymentRequest::IsValidDetailsUpdate(const PaymentDetailsUpdate& aDetails)
+{
+  nsAutoString message;
+  // Check the amount.value of detail.total
+  if (!IsNonNegativeNumber(NS_LITERAL_STRING("details.total"),
+                           aDetails.mTotal.mAmount.mValue, message)) {
+    return false;
+  }
+
+  return IsValidDetailsBase(aDetails, message);
+}
+
+bool
 PaymentRequest::IsValidDetailsBase(const PaymentDetailsBase& aDetails, nsAString& aErrorMsg)
 {
   // Check the amount.value of each item in the display items
   if (aDetails.mDisplayItems.WasPassed()) {
     const Sequence<PaymentItem>& displayItems = aDetails.mDisplayItems.Value();
     for (const PaymentItem& displayItem : displayItems) {
       if (!IsValidNumber(displayItem.mLabel,
                          displayItem.mAmount.mValue, aErrorMsg)) {
@@ -257,16 +270,17 @@ PaymentRequest::CreatePaymentRequest(nsP
   return request.forget();
 }
 
 PaymentRequest::PaymentRequest(nsPIDOMWindowInner* aWindow, const nsAString& aInternalId)
   : DOMEventTargetHelper(aWindow)
   , mInternalId(aInternalId)
   , mShippingAddress(nullptr)
   , mUpdating(false)
+  , mUpdateError(NS_OK)
   , mState(eCreated)
 {
   MOZ_ASSERT(aWindow);
 }
 
 already_AddRefed<Promise>
 PaymentRequest::CanMakePayment(ErrorResult& aRv)
 {
@@ -426,29 +440,79 @@ PaymentRequest::Abort(ErrorResult& aRv)
 
   mAbortPromise = promise;
   return promise.forget();
 }
 
 void
 PaymentRequest::RespondAbortPayment(bool aSuccess)
 {
+  // Check whether we are aborting the update:
+  //
+  // - If |mUpdateError| is not NS_OK, we are aborting the update as
+  //   |mUpdateError| was set in method |AbortUpdate|.
+  //   => Reject |mAcceptPromise| and reset |mUpdateError| to complete
+  //      the action, regardless of |aSuccess|.
+  //
+  // - Otherwise, we are handling |Abort| method call from merchant.
+  //   => Resolve/Reject |mAbortPromise| based on |aSuccess|.
+  if (NS_FAILED(mUpdateError)) {
+    RespondShowPayment(false, EmptyString(), EmptyString(), EmptyString(),
+                       EmptyString(), EmptyString(), mUpdateError);
+    mUpdateError = NS_OK;
+    return;
+  }
+
   MOZ_ASSERT(mAbortPromise);
   MOZ_ASSERT(mState == eInteractive);
 
   if (aSuccess) {
     mAbortPromise->MaybeResolve(JS::UndefinedHandleValue);
     mAbortPromise = nullptr;
     RejectShowPayment(NS_ERROR_DOM_ABORT_ERR);
   } else {
     mAbortPromise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
     mAbortPromise = nullptr;
   }
 }
 
+nsresult
+PaymentRequest::UpdatePayment(const PaymentDetailsUpdate& aDetails)
+{
+  RefPtr<PaymentRequestManager> manager = PaymentRequestManager::GetSingleton();
+  if (NS_WARN_IF(!manager)) {
+    return NS_ERROR_FAILURE;
+  }
+  nsresult rv = manager->UpdatePayment(mInternalId, aDetails);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+  return NS_OK;
+}
+
+void
+PaymentRequest::AbortUpdate(nsresult aRv)
+{
+  MOZ_ASSERT(NS_FAILED(aRv));
+
+  // Close down any remaining user interface.
+  RefPtr<PaymentRequestManager> manager = PaymentRequestManager::GetSingleton();
+  MOZ_ASSERT(manager);
+  nsresult rv = manager->AbortPayment(mInternalId);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return;
+  }
+
+  // Remember update error |aRv| and do the following steps in RespondShowPayment.
+  // 1. Set target.state to closed
+  // 2. Reject the promise target.acceptPromise with exception "aRv"
+  // 3. Abort the algorithm with update error
+  mUpdateError = aRv;
+}
+
 void
 PaymentRequest::GetId(nsAString& aRetVal) const
 {
   aRetVal = mId;
 }
 
 void
 PaymentRequest::GetInternalId(nsAString& aRetVal)
@@ -475,29 +539,76 @@ PaymentRequest::ReadyForUpdate()
 }
 
 void
 PaymentRequest::SetUpdating(bool aUpdating)
 {
   mUpdating = aUpdating;
 }
 
+nsresult
+PaymentRequest::DispatchUpdateEvent(const nsAString& aType)
+{
+  MOZ_ASSERT(ReadyForUpdate());
+
+  PaymentRequestUpdateEventInit init;
+  init.mBubbles = false;
+  init.mCancelable = false;
+
+  RefPtr<PaymentRequestUpdateEvent> event =
+    PaymentRequestUpdateEvent::Constructor(this, aType, init);
+  event->SetTrusted(true);
+
+  return DispatchDOMEvent(nullptr, event, nullptr, nullptr);
+}
+
 already_AddRefed<PaymentAddress>
 PaymentRequest::GetShippingAddress() const
 {
   RefPtr<PaymentAddress> address = mShippingAddress;
   return address.forget();
 }
 
+nsresult
+PaymentRequest::UpdateShippingAddress(const nsAString& aCountry,
+                                      const nsTArray<nsString>& aAddressLine,
+                                      const nsAString& aRegion,
+                                      const nsAString& aCity,
+                                      const nsAString& aDependentLocality,
+                                      const nsAString& aPostalCode,
+                                      const nsAString& aSortingCode,
+                                      const nsAString& aLanguageCode,
+                                      const nsAString& aOrganization,
+                                      const nsAString& aRecipient,
+                                      const nsAString& aPhone)
+{
+  mShippingAddress = new PaymentAddress(GetOwner(), aCountry, aAddressLine,
+                                        aRegion, aCity, aDependentLocality,
+                                        aPostalCode, aSortingCode, aLanguageCode,
+                                        aOrganization, aRecipient, aPhone);
+
+  // Fire shippingaddresschange event
+  return DispatchUpdateEvent(NS_LITERAL_STRING("shippingaddresschange"));
+}
+
 void
 PaymentRequest::GetShippingOption(nsAString& aRetVal) const
 {
   aRetVal = mShippingOption;
 }
 
+nsresult
+PaymentRequest::UpdateShippingOption(const nsAString& aShippingOption)
+{
+  mShippingOption = aShippingOption;
+
+  // Fire shippingaddresschange event
+  return DispatchUpdateEvent(NS_LITERAL_STRING("shippingoptionchange"));
+}
+
 Nullable<PaymentShippingType>
 PaymentRequest::GetShippingType() const
 {
   return nullptr;
 }
 
 PaymentRequest::~PaymentRequest()
 {
--- a/dom/payments/PaymentRequest.h
+++ b/dom/payments/PaymentRequest.h
@@ -7,16 +7,17 @@
 #ifndef mozilla_dom_PaymentRequest_h
 #define mozilla_dom_PaymentRequest_h
 
 #include "mozilla/DOMEventTargetHelper.h"
 #include "mozilla/dom/PaymentRequestBinding.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/ErrorResult.h"
 #include "nsWrapperCache.h"
+#include "PaymentRequestUpdateEvent.h"
 
 namespace mozilla {
 namespace dom {
 
 class EventHandlerNonNull;
 class PaymentAddress;
 class PaymentResponse;
 
@@ -45,16 +46,20 @@ public:
   static bool
   IsNonNegativeNumber(const nsAString& aItem,
                       const nsAString& aStr,
                       nsAString& aErrorMsg);
 
   static bool
   IsValidDetailsInit(const PaymentDetailsInit& aDetails,
                      nsAString& aErrorMsg);
+
+  static bool
+  IsValidDetailsUpdate(const PaymentDetailsUpdate& aDetails);
+
   static bool
   IsValidDetailsBase(const PaymentDetailsBase& aDetails,
                      nsAString& aErrorMsg);
 
   static already_AddRefed<PaymentRequest>
   Constructor(const GlobalObject& aGlobal,
               const Sequence<PaymentMethodData>& aMethodData,
               const PaymentDetailsInit& aDetails,
@@ -83,26 +88,45 @@ public:
   void SetId(const nsAString& aId);
 
   bool Equals(const nsAString& aInternalId) const;
 
   bool ReadyForUpdate();
   void SetUpdating(bool aUpdating);
 
   already_AddRefed<PaymentAddress> GetShippingAddress() const;
+  // Update mShippingAddress and fire shippingaddresschange event
+  nsresult UpdateShippingAddress(const nsAString& aCountry,
+                                 const nsTArray<nsString>& aAddressLine,
+                                 const nsAString& aRegion,
+                                 const nsAString& aCity,
+                                 const nsAString& aDependentLocality,
+                                 const nsAString& aPostalCode,
+                                 const nsAString& aSortingCode,
+                                 const nsAString& aLanguageCode,
+                                 const nsAString& aOrganization,
+                                 const nsAString& aRecipient,
+                                 const nsAString& aPhone);
+
   void GetShippingOption(nsAString& aRetVal) const;
+  nsresult UpdateShippingOption(const nsAString& aShippingOption);
+
+  nsresult UpdatePayment(const PaymentDetailsUpdate& aDetails);
+  void AbortUpdate(nsresult aRv);
 
   Nullable<PaymentShippingType> GetShippingType() const;
 
   IMPL_EVENT_HANDLER(shippingaddresschange);
   IMPL_EVENT_HANDLER(shippingoptionchange);
 
 protected:
   ~PaymentRequest();
 
+  nsresult DispatchUpdateEvent(const nsAString& aType);
+
   PaymentRequest(nsPIDOMWindowInner* aWindow, const nsAString& aInternalId);
 
   // Id for internal identification
   nsString mInternalId;
   // Id for communicating with merchant side
   // mId is initialized to details.id if it exists
   // otherwise, mId has the same value as mInternalId.
   nsString mId;
@@ -118,17 +142,17 @@ protected:
   RefPtr<PaymentAddress> mShippingAddress;
   // It is populated when the user chooses a shipping option.
   nsString mShippingOption;
 
   // "true" when there is a pending updateWith() call to update the payment request
   // and "false" otherwise.
   bool mUpdating;
   // The error is set in AbortUpdate(). The value is NS_OK by default.
-  //nsresult mUpdateError;
+  nsresult mUpdateError;
 
   enum {
     eUnknown,
     eCreated,
     eInteractive,
     eClosed
   } mState;
 };
--- a/dom/payments/PaymentRequestData.cpp
+++ b/dom/payments/PaymentRequestData.cpp
@@ -650,11 +650,121 @@ PaymentRequest::GetPaymentOptions(nsIPay
 
 NS_IMETHODIMP
 PaymentRequest::UpdatePaymentDetails(nsIPaymentDetails* aPaymentDetails)
 {
   MOZ_ASSERT(aPaymentDetails);
   return mPaymentDetails->Update(aPaymentDetails);
 }
 
+/* PaymentAddress */
+
+NS_IMPL_ISUPPORTS(PaymentAddress, nsIPaymentAddress)
+
+nsresult
+PaymentAddress::Init(const nsAString& aCountry,
+                     nsIArray* aAddressLine,
+                     const nsAString& aRegion,
+                     const nsAString& aCity,
+                     const nsAString& aDependentLocality,
+                     const nsAString& aPostalCode,
+                     const nsAString& aSortingCode,
+                     const nsAString& aLanguageCode,
+                     const nsAString& aOrganization,
+                     const nsAString& aRecipient,
+                     const nsAString& aPhone)
+{
+  mCountry = aCountry;
+  mAddressLine = aAddressLine;
+  mRegion = aRegion;
+  mCity = aCity;
+  mDependentLocality = aDependentLocality;
+  mPostalCode = aPostalCode;
+  mSortingCode = aSortingCode;
+  mLanguageCode = aLanguageCode;
+  mOrganization = aOrganization;
+  mRecipient = aRecipient;
+  mPhone = aPhone;
+  return NS_OK;
+}
+
+nsresult
+PaymentAddress::GetCountry(nsAString& aCountry)
+{
+  aCountry = mCountry;
+  return NS_OK;
+}
+
+nsresult
+PaymentAddress::GetAddressLine(nsIArray** aAddressLine)
+{
+  NS_ENSURE_ARG_POINTER(aAddressLine);
+  nsCOMPtr<nsIArray> addressLine = mAddressLine;
+  addressLine.forget(aAddressLine);
+  return NS_OK;
+}
+
+nsresult
+PaymentAddress::GetRegion(nsAString& aRegion)
+{
+  aRegion = mRegion;
+  return NS_OK;
+}
+
+nsresult
+PaymentAddress::GetCity(nsAString& aCity)
+{
+  aCity = mCity;
+  return NS_OK;
+}
+
+nsresult
+PaymentAddress::GetDependentLocality(nsAString& aDependentLocality)
+{
+  aDependentLocality = mDependentLocality;
+  return NS_OK;
+}
+
+nsresult
+PaymentAddress::GetPostalCode(nsAString& aPostalCode)
+{
+  aPostalCode = mPostalCode;
+  return NS_OK;
+}
+
+nsresult
+PaymentAddress::GetSortingCode(nsAString& aSortingCode)
+{
+  aSortingCode = mSortingCode;
+  return NS_OK;
+}
+
+nsresult
+PaymentAddress::GetLanguageCode(nsAString& aLanguageCode)
+{
+  aLanguageCode = mLanguageCode;
+  return NS_OK;
+}
+
+nsresult
+PaymentAddress::GetOrganization(nsAString& aOrganization)
+{
+  aOrganization = mOrganization;
+  return NS_OK;
+}
+
+nsresult
+PaymentAddress::GetRecipient(nsAString& aRecipient)
+{
+  aRecipient = mRecipient;
+  return NS_OK;
+}
+
+nsresult
+PaymentAddress::GetPhone(nsAString& aPhone)
+{
+  aPhone = mPhone;
+  return NS_OK;
+}
+
 } // end of namespace payment
 } // end of namespace dom
 } // end of namespace mozilla
--- a/dom/payments/PaymentRequestData.h
+++ b/dom/payments/PaymentRequestData.h
@@ -2,16 +2,17 @@
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_PaymentRequestData_h
 #define mozilla_dom_PaymentRequestData_h
 
+#include "nsIPaymentAddress.h"
 #include "nsIPaymentRequest.h"
 #include "nsCOMPtr.h"
 #include "mozilla/dom/PPaymentRequest.h"
 
 namespace mozilla {
 namespace dom {
 namespace payments {
 
@@ -187,13 +188,37 @@ private:
 
   uint64_t mTabId;
   nsString mRequestId;
   nsCOMPtr<nsIArray> mPaymentMethods;
   nsCOMPtr<nsIPaymentDetails> mPaymentDetails;
   nsCOMPtr<nsIPaymentOptions> mPaymentOptions;
 };
 
+class PaymentAddress final : public nsIPaymentAddress
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIPAYMENTADDRESS
+
+  PaymentAddress() = default;
+
+private:
+  ~PaymentAddress() = default;
+
+  nsString mCountry;
+  nsCOMPtr<nsIArray> mAddressLine;
+  nsString mRegion;
+  nsString mCity;
+  nsString mDependentLocality;
+  nsString mPostalCode;
+  nsString mSortingCode;
+  nsString mLanguageCode;
+  nsString mOrganization;
+  nsString mRecipient;
+  nsString mPhone;
+};
+
 } // end of namespace payment
 } // end of namespace dom
 } // end of namespace mozilla
 
 #endif
--- a/dom/payments/PaymentRequestManager.cpp
+++ b/dom/payments/PaymentRequestManager.cpp
@@ -1,42 +1,32 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "PaymentRequestManager.h"
+#include "PaymentRequestUtils.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/dom/ContentChild.h"
 #include "mozilla/dom/TabChild.h"
 #include "mozilla/dom/PaymentRequestChild.h"
 #include "nsContentUtils.h"
-#include "nsIJSON.h"
 #include "nsString.h"
 
 namespace mozilla {
 namespace dom {
 namespace {
 
 /*
  *  Following Convert* functions are used for convert PaymentRequest structs
  *  to transferable structs for IPC.
  */
 nsresult
-SerializeFromJSObject(JSContext* aCx, JS::HandleObject aObject, nsAString& aSerializedObject){
-  nsCOMPtr<nsIJSON> serializer = do_CreateInstance("@mozilla.org/dom/json;1");
-  if (NS_WARN_IF(!serializer)) {
-    return NS_ERROR_FAILURE;
-  }
-  JS::RootedValue value(aCx, JS::ObjectValue(*aObject));
-  return serializer->EncodeFromJSVal(value.address(), aCx, aSerializedObject);
-}
-
-nsresult
 ConvertMethodData(const PaymentMethodData& aMethodData,
                   IPCPaymentMethodData& aIPCMethodData)
 {
   // Convert Sequence<nsString> to nsTArray<nsString>
   nsTArray<nsString> supportedMethods;
   for (const nsString& method : aMethodData.mSupportedMethods) {
     supportedMethods.AppendElement(method);
   }
@@ -184,16 +174,51 @@ ConvertDetailsInit(const PaymentDetailsI
                                   modifiers,
                                   EmptyString(), // error message
                                   aDetails.mDisplayItems.WasPassed(),
                                   aDetails.mShippingOptions.WasPassed(),
                                   aDetails.mModifiers.WasPassed());
   return NS_OK;
 }
 
+nsresult
+ConvertDetailsUpdate(const PaymentDetailsUpdate& aDetails,
+                     IPCPaymentDetails& aIPCDetails)
+{
+  // Convert PaymentDetailsBase members
+  nsTArray<IPCPaymentItem> displayItems;
+  nsTArray<IPCPaymentShippingOption> shippingOptions;
+  nsTArray<IPCPaymentDetailsModifier> modifiers;
+  nsresult rv = ConvertDetailsBase(aDetails, displayItems, shippingOptions, modifiers);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  // Convert required |total|
+  IPCPaymentItem total;
+  ConvertItem(aDetails.mTotal, total);
+
+  // Convert |error|
+  nsString error(EmptyString());
+  if (aDetails.mError.WasPassed()) {
+    error = aDetails.mError.Value();
+  }
+
+  aIPCDetails = IPCPaymentDetails(EmptyString(), // id
+                                  total,
+                                  displayItems,
+                                  shippingOptions,
+                                  modifiers,
+                                  error,
+                                  aDetails.mDisplayItems.WasPassed(),
+                                  aDetails.mShippingOptions.WasPassed(),
+                                  aDetails.mModifiers.WasPassed());
+  return NS_OK;
+}
+
 void
 ConvertOptions(const PaymentOptions& aOptions,
                IPCPaymentOptions& aIPCOption)
 {
   uint8_t shippingTypeIndex = static_cast<uint8_t>(aOptions.mShippingType);
   nsString shippingType(NS_LITERAL_STRING("shipping"));
   if (shippingTypeIndex < ArrayLength(PaymentShippingTypeValues::strings)) {
     shippingType.AssignASCII(
@@ -463,64 +488,91 @@ PaymentRequestManager::CompletePayment(c
 
   nsAutoString requestId(aRequestId);
   IPCPaymentCompleteActionRequest action(requestId, completeStatusString);
 
   return SendRequestPayment(request, action);
 }
 
 nsresult
+PaymentRequestManager::UpdatePayment(const nsAString& aRequestId,
+                                     const PaymentDetailsUpdate& aDetails)
+{
+  RefPtr<PaymentRequest> request = GetPaymentRequestById(aRequestId);
+  if (!request) {
+    return NS_ERROR_UNEXPECTED;
+  }
+
+  IPCPaymentDetails details;
+  nsresult rv = ConvertDetailsUpdate(aDetails, details);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  nsAutoString requestId(aRequestId);
+  IPCPaymentUpdateActionRequest action(requestId, details);
+  return SendRequestPayment(request, action);
+}
+
+nsresult
 PaymentRequestManager::RespondPayment(const IPCPaymentActionResponse& aResponse)
 {
   switch (aResponse.type()) {
     case IPCPaymentActionResponse::TIPCPaymentCanMakeActionResponse: {
-      IPCPaymentCanMakeActionResponse response = aResponse;
+      const IPCPaymentCanMakeActionResponse& response = aResponse;
       RefPtr<PaymentRequest> request = GetPaymentRequestById(response.requestId());
       if (NS_WARN_IF(!request)) {
         return NS_ERROR_FAILURE;
       }
       request->RespondCanMakePayment(response.result());
       nsresult rv = ReleasePaymentChild(request);
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
       break;
     }
     case IPCPaymentActionResponse::TIPCPaymentShowActionResponse: {
-      IPCPaymentShowActionResponse response = aResponse;
+      const IPCPaymentShowActionResponse& response = aResponse;
       RefPtr<PaymentRequest> request = GetPaymentRequestById(response.requestId());
       if (NS_WARN_IF(!request)) {
         return NS_ERROR_FAILURE;
       }
       request->RespondShowPayment(response.isAccepted(),
                                   response.methodName(),
                                   response.data(),
                                   response.payerName(),
                                   response.payerEmail(),
                                   response.payerPhone());
+      if (!response.isAccepted()) {
+        mRequestQueue.RemoveElement(request);
+        nsresult rv = ReleasePaymentChild(request);
+        if (NS_WARN_IF(NS_FAILED(rv))) {
+          return rv;
+        }
+      }
       break;
     }
     case IPCPaymentActionResponse::TIPCPaymentAbortActionResponse: {
-      IPCPaymentAbortActionResponse response = aResponse;
+      const IPCPaymentAbortActionResponse& response = aResponse;
       RefPtr<PaymentRequest> request = GetPaymentRequestById(response.requestId());
       if (NS_WARN_IF(!request)) {
         return NS_ERROR_FAILURE;
       }
       request->RespondAbortPayment(response.isSucceeded());
       if (response.isSucceeded()) {
         mRequestQueue.RemoveElement(request);
         nsresult rv = ReleasePaymentChild(request);
         if (NS_WARN_IF(NS_FAILED(rv))) {
           return rv;
         }
       }
       break;
     }
     case IPCPaymentActionResponse::TIPCPaymentCompleteActionResponse: {
-      IPCPaymentCompleteActionResponse response = aResponse;
+      const IPCPaymentCompleteActionResponse& response = aResponse;
       RefPtr<PaymentRequest> request = GetPaymentRequestById(response.requestId());
       if (NS_WARN_IF(!request)) {
         return NS_ERROR_FAILURE;
       }
       request->RespondComplete();
       mRequestQueue.RemoveElement(request);
       nsresult rv = ReleasePaymentChild(request);
       if (NS_WARN_IF(NS_FAILED(rv))) {
@@ -530,10 +582,42 @@ PaymentRequestManager::RespondPayment(co
     }
     default: {
       return NS_ERROR_FAILURE;
     }
   }
   return NS_OK;
 }
 
+nsresult
+PaymentRequestManager::ChangeShippingAddress(const nsAString& aRequestId,
+                                             const IPCPaymentAddress& aAddress)
+{
+  RefPtr<PaymentRequest> request = GetPaymentRequestById(aRequestId);
+  if (NS_WARN_IF(!request)) {
+    return NS_ERROR_FAILURE;
+  }
+  return request->UpdateShippingAddress(aAddress.country(),
+                                        aAddress.addressLine(),
+                                        aAddress.region(),
+                                        aAddress.city(),
+                                        aAddress.dependentLocality(),
+                                        aAddress.postalCode(),
+                                        aAddress.sortingCode(),
+                                        aAddress.languageCode(),
+                                        aAddress.organization(),
+                                        aAddress.recipient(),
+                                        aAddress.phone());
+}
+
+nsresult
+PaymentRequestManager::ChangeShippingOption(const nsAString& aRequestId,
+                                            const nsAString& aOption)
+{
+  RefPtr<PaymentRequest> request = GetPaymentRequestById(aRequestId);
+  if (NS_WARN_IF(!request)) {
+    return NS_ERROR_FAILURE;
+  }
+  return request->UpdateShippingOption(aOption);
+}
+
 } // end of namespace dom
 } // end of namespace mozilla
--- a/dom/payments/PaymentRequestManager.h
+++ b/dom/payments/PaymentRequestManager.h
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_PaymentRequestManager_h
 #define mozilla_dom_PaymentRequestManager_h
 
 #include "nsISupports.h"
 #include "PaymentRequest.h"
 #include "mozilla/dom/PaymentRequestBinding.h"
+#include "mozilla/dom/PaymentRequestUpdateEventBinding.h"
 #include "mozilla/dom/PaymentResponseBinding.h"
 #include "nsCOMPtr.h"
 #include "nsTArray.h"
 
 namespace mozilla {
 namespace dom {
 
 class PaymentRequestChild;
@@ -46,18 +47,24 @@ public:
                 const PaymentOptions& aOptions,
                 PaymentRequest** aRequest);
 
   nsresult CanMakePayment(const nsAString& aRequestId);
   nsresult ShowPayment(const nsAString& aRequestId);
   nsresult AbortPayment(const nsAString& aRequestId);
   nsresult CompletePayment(const nsAString& aRequestId,
                            const PaymentComplete& aComplete);
+  nsresult UpdatePayment(const nsAString& aRequestId,
+                         const PaymentDetailsUpdate& aDetails);
 
   nsresult RespondPayment(const IPCPaymentActionResponse& aResponse);
+  nsresult ChangeShippingAddress(const nsAString& aRequestId,
+                                 const IPCPaymentAddress& aAddress);
+  nsresult ChangeShippingOption(const nsAString& aRequestId,
+                                const nsAString& aOption);
 
   nsresult
   ReleasePaymentChild(PaymentRequestChild* aPaymentChild);
 
 private:
   PaymentRequestManager() = default;
   ~PaymentRequestManager() = default;
 
--- a/dom/payments/PaymentRequestModule.cpp
+++ b/dom/payments/PaymentRequestModule.cpp
@@ -2,78 +2,91 @@
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/ModuleUtils.h"
 #include "PaymentActionRequest.h"
 #include "PaymentActionResponse.h"
+#include "PaymentRequestData.h"
 #include "PaymentRequestService.h"
 
 using mozilla::dom::PaymentActionRequest;
 using mozilla::dom::PaymentCreateActionRequest;
 using mozilla::dom::PaymentCompleteActionRequest;
+using mozilla::dom::PaymentUpdateActionRequest;
 using mozilla::dom::PaymentCanMakeActionResponse;
 using mozilla::dom::PaymentAbortActionResponse;
 using mozilla::dom::PaymentShowActionResponse;
 using mozilla::dom::PaymentCompleteActionResponse;
+using mozilla::dom::payments::PaymentAddress;
 using mozilla::dom::PaymentRequestService;
 
 NS_GENERIC_FACTORY_CONSTRUCTOR(PaymentActionRequest)
 NS_GENERIC_FACTORY_CONSTRUCTOR(PaymentCreateActionRequest)
 NS_GENERIC_FACTORY_CONSTRUCTOR(PaymentCompleteActionRequest)
+NS_GENERIC_FACTORY_CONSTRUCTOR(PaymentUpdateActionRequest)
 NS_GENERIC_FACTORY_CONSTRUCTOR(PaymentCanMakeActionResponse)
 NS_GENERIC_FACTORY_CONSTRUCTOR(PaymentAbortActionResponse)
 NS_GENERIC_FACTORY_CONSTRUCTOR(PaymentShowActionResponse)
 NS_GENERIC_FACTORY_CONSTRUCTOR(PaymentCompleteActionResponse)
+NS_GENERIC_FACTORY_CONSTRUCTOR(PaymentAddress)
 NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(PaymentRequestService,
                                          PaymentRequestService::GetSingleton)
 
 NS_DEFINE_NAMED_CID(NS_PAYMENT_ACTION_REQUEST_CID);
 NS_DEFINE_NAMED_CID(NS_PAYMENT_CREATE_ACTION_REQUEST_CID);
 NS_DEFINE_NAMED_CID(NS_PAYMENT_COMPLETE_ACTION_REQUEST_CID);
+NS_DEFINE_NAMED_CID(NS_PAYMENT_UPDATE_ACTION_REQUEST_CID);
 NS_DEFINE_NAMED_CID(NS_PAYMENT_CANMAKE_ACTION_RESPONSE_CID);
 NS_DEFINE_NAMED_CID(NS_PAYMENT_ABORT_ACTION_RESPONSE_CID);
 NS_DEFINE_NAMED_CID(NS_PAYMENT_SHOW_ACTION_RESPONSE_CID);
 NS_DEFINE_NAMED_CID(NS_PAYMENT_COMPLETE_ACTION_RESPONSE_CID);
+NS_DEFINE_NAMED_CID(NS_PAYMENT_ADDRESS_CID);
 NS_DEFINE_NAMED_CID(NS_PAYMENT_REQUEST_SERVICE_CID);
 
 static const mozilla::Module::CIDEntry kPaymentRequestCIDs[] = {
   { &kNS_PAYMENT_ACTION_REQUEST_CID, false, nullptr, PaymentActionRequestConstructor},
   { &kNS_PAYMENT_CREATE_ACTION_REQUEST_CID, false, nullptr, PaymentCreateActionRequestConstructor},
   { &kNS_PAYMENT_COMPLETE_ACTION_REQUEST_CID, false, nullptr, PaymentCompleteActionRequestConstructor},
+  { &kNS_PAYMENT_UPDATE_ACTION_REQUEST_CID, false, nullptr, PaymentUpdateActionRequestConstructor},
   { &kNS_PAYMENT_CANMAKE_ACTION_RESPONSE_CID, false, nullptr, PaymentCanMakeActionResponseConstructor},
   { &kNS_PAYMENT_ABORT_ACTION_RESPONSE_CID, false, nullptr, PaymentAbortActionResponseConstructor},
   { &kNS_PAYMENT_SHOW_ACTION_RESPONSE_CID, false, nullptr, PaymentShowActionResponseConstructor},
   { &kNS_PAYMENT_COMPLETE_ACTION_RESPONSE_CID, false, nullptr, PaymentCompleteActionResponseConstructor},
+  { &kNS_PAYMENT_ADDRESS_CID, false, nullptr, PaymentAddressConstructor},
   { &kNS_PAYMENT_REQUEST_SERVICE_CID, true, nullptr, PaymentRequestServiceConstructor },
   { nullptr }
 };
 
 static const mozilla::Module::ContractIDEntry kPaymentRequestContracts[] = {
   { NS_PAYMENT_ACTION_REQUEST_CONTRACT_ID, &kNS_PAYMENT_ACTION_REQUEST_CID },
   { NS_PAYMENT_CREATE_ACTION_REQUEST_CONTRACT_ID, &kNS_PAYMENT_CREATE_ACTION_REQUEST_CID },
   { NS_PAYMENT_COMPLETE_ACTION_REQUEST_CONTRACT_ID, &kNS_PAYMENT_COMPLETE_ACTION_REQUEST_CID },
+  { NS_PAYMENT_UPDATE_ACTION_REQUEST_CONTRACT_ID, &kNS_PAYMENT_UPDATE_ACTION_REQUEST_CID },
   { NS_PAYMENT_CANMAKE_ACTION_RESPONSE_CONTRACT_ID, &kNS_PAYMENT_CANMAKE_ACTION_RESPONSE_CID },
   { NS_PAYMENT_ABORT_ACTION_RESPONSE_CONTRACT_ID, &kNS_PAYMENT_ABORT_ACTION_RESPONSE_CID },
   { NS_PAYMENT_SHOW_ACTION_RESPONSE_CONTRACT_ID, &kNS_PAYMENT_SHOW_ACTION_RESPONSE_CID },
   { NS_PAYMENT_COMPLETE_ACTION_RESPONSE_CONTRACT_ID, &kNS_PAYMENT_COMPLETE_ACTION_RESPONSE_CID },
+  { NS_PAYMENT_ADDRESS_CONTRACT_ID, &kNS_PAYMENT_ADDRESS_CID },
   { NS_PAYMENT_REQUEST_SERVICE_CONTRACT_ID, &kNS_PAYMENT_REQUEST_SERVICE_CID },
   { nullptr }
 };
 
 static const mozilla::Module::CategoryEntry kPaymentRequestCategories[] = {
   { "payment-request", "PaymentActionRequest", NS_PAYMENT_ACTION_REQUEST_CONTRACT_ID },
   { "payment-request", "PaymentCreateActionRequest", NS_PAYMENT_CREATE_ACTION_REQUEST_CONTRACT_ID },
   { "payment-request", "PaymentCompleteActionRequest", NS_PAYMENT_COMPLETE_ACTION_REQUEST_CONTRACT_ID },
+  { "payment-request", "PaymentUpdateActionRequest", NS_PAYMENT_UPDATE_ACTION_REQUEST_CONTRACT_ID },
   { "payment-request", "PaymentCanMakeActionResponse", NS_PAYMENT_CANMAKE_ACTION_RESPONSE_CONTRACT_ID },
   { "payment-request", "PaymentAbortActionResponse", NS_PAYMENT_ABORT_ACTION_RESPONSE_CONTRACT_ID },
   { "payment-request", "PaymentShowActionResponse", NS_PAYMENT_SHOW_ACTION_RESPONSE_CONTRACT_ID },
   { "payment-request", "PaymentCompleteActionResponse", NS_PAYMENT_COMPLETE_ACTION_RESPONSE_CONTRACT_ID },
+  { "payment-request", "PaymentAddress", NS_PAYMENT_ADDRESS_CONTRACT_ID },
   { "payment-request", "PaymentRequestService", NS_PAYMENT_REQUEST_SERVICE_CONTRACT_ID },
   { nullptr }
 };
 
 static const mozilla::Module kPaymentRequestModule = {
   mozilla::Module::kVersion,
   kPaymentRequestCIDs,
   kPaymentRequestContracts,
--- a/dom/payments/PaymentRequestService.cpp
+++ b/dom/payments/PaymentRequestService.cpp
@@ -164,26 +164,31 @@ PaymentRequestService::CallTestingUIActi
       case nsIPaymentActionRequest::ABORT_ACTION: {
         rv = mTestingUIService->AbortPayment(aRequestId, getter_AddRefs(response));
         break;
       }
       case nsIPaymentActionRequest::COMPLETE_ACTION: {
         rv = mTestingUIService->CompletePayment(aRequestId, getter_AddRefs(response));
         break;
       }
+      case nsIPaymentActionRequest::UPDATE_ACTION: {
+        rv = mTestingUIService->UpdatePayment(aRequestId, getter_AddRefs(response));
+        break;
+      }
       default : {
         return NS_ERROR_FAILURE;
       }
     }
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
   } else {
     // Since there is no UI implementation and no testing UI Service is registered,
-    // set false response for canMakePayment() and ABORT_SUCCEEDED for abort()
+    // set false response for canMakePayment(), ABORT_SUCCEEDED for abort() and
+    // COMPLETE_SUCCEEDED for complete().
     switch (aActionType) {
       case nsIPaymentActionRequest::CANMAKE_ACTION: {
         nsCOMPtr<nsIPaymentCanMakeActionResponse> canMakeResponse =
           do_CreateInstance(NS_PAYMENT_CANMAKE_ACTION_RESPONSE_CONTRACT_ID);
         MOZ_ASSERT(canMakeResponse);
         rv = canMakeResponse->Init(aRequestId, false);
         NS_ENSURE_SUCCESS(rv, rv);
         response = do_QueryInterface(canMakeResponse);
@@ -195,16 +200,26 @@ PaymentRequestService::CallTestingUIActi
           do_CreateInstance(NS_PAYMENT_ABORT_ACTION_RESPONSE_CONTRACT_ID);
         MOZ_ASSERT(abortResponse);
         rv = abortResponse->Init(aRequestId, nsIPaymentActionResponse::ABORT_SUCCEEDED);
         NS_ENSURE_SUCCESS(rv, rv);
         response = do_QueryInterface(abortResponse);
         MOZ_ASSERT(response);
         break;
       }
+      case nsIPaymentActionRequest::COMPLETE_ACTION: {
+        nsCOMPtr<nsIPaymentCompleteActionResponse> completeResponse =
+          do_CreateInstance(NS_PAYMENT_COMPLETE_ACTION_RESPONSE_CONTRACT_ID);
+        MOZ_ASSERT(completeResponse);
+        rv = completeResponse->Init(aRequestId, nsIPaymentActionResponse::COMPLETE_SUCCEEDED);
+        NS_ENSURE_SUCCESS(rv, rv);
+        response = do_QueryInterface(completeResponse);
+        MOZ_ASSERT(response);
+        break;
+      }
       default : {
         break;
       }
     }
   }
   if (response) {
     rv = RespondPayment(response);
     if (NS_WARN_IF(NS_FAILED(rv))) {
@@ -257,37 +272,29 @@ PaymentRequestService::RequestPayment(ns
 
   switch (type) {
     case nsIPaymentActionRequest::CREATE_ACTION: {
       nsCOMPtr<nsIPaymentCreateActionRequest> request =
         do_QueryInterface(aRequest);
       MOZ_ASSERT(request);
       uint64_t tabId;
       rv = request->GetTabId(&tabId);
-      if (NS_WARN_IF(NS_FAILED(rv))) {
-        return rv;
-      }
+      NS_ENSURE_SUCCESS(rv, rv);
 
       nsCOMPtr<nsIArray> methodData;
       rv = request->GetMethodData(getter_AddRefs(methodData));
-      if (NS_WARN_IF(NS_FAILED(rv))) {
-        return NS_ERROR_FAILURE;
-      }
+      NS_ENSURE_SUCCESS(rv, rv);
 
       nsCOMPtr<nsIPaymentDetails> details;
       rv = request->GetDetails(getter_AddRefs(details));
-      if (NS_WARN_IF(NS_FAILED(rv))) {
-        return NS_ERROR_FAILURE;
-      }
+      NS_ENSURE_SUCCESS(rv, rv);
 
       nsCOMPtr<nsIPaymentOptions> options;
       rv = request->GetOptions(getter_AddRefs(options));
-      if (NS_WARN_IF(NS_FAILED(rv))) {
-        return NS_ERROR_FAILURE;
-      }
+      NS_ENSURE_SUCCESS(rv, rv);
 
       nsCOMPtr<nsIPaymentRequest> payment =
         new payments::PaymentRequest(tabId, requestId, methodData, details, options);
 
       if (!mRequestQueue.AppendElement(payment, mozilla::fallible)) {
         return NS_ERROR_OUT_OF_MEMORY;
       }
       break;
@@ -307,16 +314,41 @@ PaymentRequestService::RequestPayment(ns
     case nsIPaymentActionRequest::ABORT_ACTION:
     case nsIPaymentActionRequest::COMPLETE_ACTION: {
       rv = CallTestingUIAction(requestId, type);
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return NS_ERROR_FAILURE;
       }
       break;
     }
+    case nsIPaymentActionRequest::UPDATE_ACTION: {
+      nsCOMPtr<nsIPaymentUpdateActionRequest> request = do_QueryInterface(aRequest);
+      MOZ_ASSERT(request);
+
+      nsCOMPtr<nsIPaymentDetails> details;
+      rv = request->GetDetails(getter_AddRefs(details));
+      NS_ENSURE_SUCCESS(rv, rv);
+
+      rv = request->GetRequestId(requestId);
+      NS_ENSURE_SUCCESS(rv, rv);
+      nsCOMPtr<nsIPaymentRequest> payment;
+      rv = GetPaymentRequestById(requestId, getter_AddRefs(payment));
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return rv;
+      }
+      rv = payment->UpdatePaymentDetails(details);
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return rv;
+      }
+      rv = CallTestingUIAction(requestId, type);
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return NS_ERROR_FAILURE;
+      }
+      break;
+    }
     default: {
       return NS_ERROR_FAILURE;
     }
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
@@ -369,16 +401,55 @@ PaymentRequestService::RespondPayment(ns
     }
     default: {
       break;
     }
   }
   return NS_OK;
 }
 
+NS_IMETHODIMP
+PaymentRequestService::ChangeShippingAddress(const nsAString& aRequestId,
+                                             nsIPaymentAddress* aAddress)
+{
+  nsCOMPtr<nsIPaymentActionCallback> callback;
+  if (!mCallbackHashtable.Get(aRequestId, getter_AddRefs(callback))) {
+    return NS_ERROR_FAILURE;
+  }
+  if (NS_WARN_IF(!callback)) {
+    return NS_ERROR_FAILURE;
+  }
+
+  nsresult rv = callback->ChangeShippingAddress(aRequestId, aAddress);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentRequestService::ChangeShippingOption(const nsAString& aRequestId,
+                                            const nsAString& aOption)
+{
+  nsCOMPtr<nsIPaymentActionCallback> callback;
+  if (!mCallbackHashtable.Get(aRequestId, getter_AddRefs(callback))) {
+    return NS_ERROR_FAILURE;
+  }
+  if (NS_WARN_IF(!callback)) {
+    return NS_ERROR_FAILURE;
+  }
+
+  nsresult rv = callback->ChangeShippingOption(aRequestId, aOption);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  return NS_OK;
+}
+
 nsresult
 PaymentRequestService::SetActionCallback(const nsAString& aRequestId,
                                          nsIPaymentActionCallback* aCallback)
 {
   NS_ENSURE_ARG_POINTER(aCallback);
   nsCOMPtr<nsIPaymentActionCallback> callback;
   if (mCallbackHashtable.Get(aRequestId, getter_AddRefs(callback))) {
     mCallbackHashtable.Remove(aRequestId);
new file mode 100644
--- /dev/null
+++ b/dom/payments/PaymentRequestUpdateEvent.cpp
@@ -0,0 +1,139 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/dom/PaymentRequestUpdateEvent.h"
+
+namespace mozilla {
+namespace dom {
+
+NS_IMPL_CYCLE_COLLECTION_INHERITED(PaymentRequestUpdateEvent, Event, mRequest)
+
+NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(PaymentRequestUpdateEvent, Event)
+NS_IMPL_CYCLE_COLLECTION_TRACE_END
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(PaymentRequestUpdateEvent)
+NS_INTERFACE_MAP_END_INHERITING(Event)
+
+NS_IMPL_ADDREF_INHERITED(PaymentRequestUpdateEvent, Event)
+NS_IMPL_RELEASE_INHERITED(PaymentRequestUpdateEvent, Event)
+
+already_AddRefed<PaymentRequestUpdateEvent>
+PaymentRequestUpdateEvent::Constructor(mozilla::dom::EventTarget* aOwner,
+                                       const nsAString& aType,
+                                       const PaymentRequestUpdateEventInit& aEventInitDict)
+{
+  RefPtr<PaymentRequestUpdateEvent> e = new PaymentRequestUpdateEvent(aOwner);
+  bool trusted = e->Init(aOwner);
+  e->InitEvent(aType, aEventInitDict.mBubbles, aEventInitDict.mCancelable);
+  e->SetTrusted(trusted);
+  e->SetComposed(aEventInitDict.mComposed);
+  return e.forget();
+}
+
+already_AddRefed<PaymentRequestUpdateEvent>
+PaymentRequestUpdateEvent::Constructor(const GlobalObject& aGlobal,
+                                       const nsAString& aType,
+                                       const PaymentRequestUpdateEventInit& aEventInitDict,
+                                       ErrorResult& aRv)
+{
+  nsCOMPtr<mozilla::dom::EventTarget> owner = do_QueryInterface(aGlobal.GetAsSupports());
+  return Constructor(owner, aType, aEventInitDict);
+}
+
+PaymentRequestUpdateEvent::PaymentRequestUpdateEvent(EventTarget* aOwner)
+  : Event(aOwner, nullptr, nullptr)
+  , mWaitForUpdate(false)
+{
+  MOZ_ASSERT(aOwner);
+
+  // event's target should be a PaymentRequest object
+  mRequest = static_cast<PaymentRequest *>(aOwner);
+}
+
+void
+PaymentRequestUpdateEvent::ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue)
+{
+  MOZ_ASSERT(mRequest);
+
+  if (NS_WARN_IF(!aValue.isObject()) || !mWaitForUpdate) {
+    return;
+  }
+
+  // Converting value to a PaymentDetailsUpdate dictionary
+  PaymentDetailsUpdate details;
+  if (!details.Init(aCx, aValue)) {
+    return;
+  }
+
+  // Validate and canonicalize the details
+  if (!mRequest->IsValidDetailsUpdate(details)) {
+    mRequest->AbortUpdate(NS_ERROR_TYPE_ERR);
+    return;
+  }
+
+  // [TODO]
+  // If the data member of modifier is present,
+  // let serializedData be the result of JSON-serializing modifier.data into a string.
+  // null if it is not.
+
+  // Update the PaymentRequest with the new details
+  if (NS_FAILED(mRequest->UpdatePayment(details))) {
+    mRequest->AbortUpdate(NS_ERROR_DOM_ABORT_ERR);
+    return;
+  }
+  mWaitForUpdate = false;
+  mRequest->SetUpdating(false);
+}
+
+void
+PaymentRequestUpdateEvent::RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue)
+{
+  MOZ_ASSERT(mRequest);
+
+  mRequest->AbortUpdate(NS_ERROR_DOM_ABORT_ERR);
+  mWaitForUpdate = false;
+  mRequest->SetUpdating(false);
+}
+
+void
+PaymentRequestUpdateEvent::UpdateWith(Promise& aPromise, ErrorResult& aRv)
+{
+  MOZ_ASSERT(mRequest);
+
+  if (mWaitForUpdate || !mRequest->ReadyForUpdate() ||
+      !mEvent->mFlags.mIsBeingDispatched) {
+    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
+    return;
+  }
+
+  aPromise.AppendNativeHandler(this);
+
+  StopPropagation();
+  StopImmediatePropagation();
+  mWaitForUpdate = true;
+  mRequest->SetUpdating(true);
+}
+
+bool
+PaymentRequestUpdateEvent::IsTrusted() const
+{
+  return true;
+}
+
+PaymentRequestUpdateEvent::~PaymentRequestUpdateEvent()
+{
+}
+
+JSObject*
+PaymentRequestUpdateEvent::WrapObjectInternal(JSContext* aCx,
+                                              JS::Handle<JSObject*> aGivenProto)
+{
+  return PaymentRequestUpdateEventBinding::Wrap(aCx, this, aGivenProto);
+}
+
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/payments/PaymentRequestUpdateEvent.h
@@ -0,0 +1,66 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_PaymentRequestUpdateEvent_h
+#define mozilla_dom_PaymentRequestUpdateEvent_h
+
+#include "mozilla/Attributes.h"
+#include "mozilla/ErrorResult.h"
+#include "mozilla/dom/Event.h"
+#include "mozilla/dom/PaymentRequestUpdateEventBinding.h"
+#include "mozilla/dom/PromiseNativeHandler.h"
+
+namespace mozilla {
+namespace dom {
+
+class Promise;
+
+class PaymentRequestUpdateEvent final : public Event
+                                      , public PromiseNativeHandler
+{
+public:
+  NS_DECL_ISUPPORTS_INHERITED
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(PaymentRequestUpdateEvent, Event)
+
+  explicit PaymentRequestUpdateEvent(EventTarget* aOwner);
+
+  virtual JSObject*
+  WrapObjectInternal(JSContext* aCx,
+                     JS::Handle<JSObject*> aGivenProto) override;
+
+  virtual void
+  ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override;
+  virtual void
+  RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override;
+
+  static already_AddRefed<PaymentRequestUpdateEvent>
+  Constructor(EventTarget* aOwner,
+              const nsAString& aType,
+              const PaymentRequestUpdateEventInit& aEventInitDict);
+
+  static already_AddRefed<PaymentRequestUpdateEvent>
+  Constructor(const GlobalObject& aGlobal,
+              const nsAString& aType,
+              const PaymentRequestUpdateEventInit& aEventInitDict,
+              ErrorResult& aRv);
+
+  void UpdateWith(Promise& aPromise, ErrorResult& aRv);
+
+  bool IsTrusted() const;
+
+protected:
+  ~PaymentRequestUpdateEvent();
+
+private:
+  // Indicating whether an updateWith()-initiated update is currently in progress.
+  bool mWaitForUpdate;
+  RefPtr<PaymentRequest> mRequest;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_PaymentRequestUpdateEvent_h
--- a/dom/payments/PaymentRequestUtils.cpp
+++ b/dom/payments/PaymentRequestUtils.cpp
@@ -3,21 +3,52 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsArrayUtils.h"
 #include "PaymentRequestUtils.h"
 #include "nsIMutableArray.h"
 #include "nsISupportsPrimitives.h"
+#include "nsIJSON.h"
 
 namespace mozilla {
 namespace dom {
 
 nsresult
+SerializeFromJSObject(JSContext* aCx, JS::HandleObject aObject, nsAString& aSerializedObject) {
+  nsCOMPtr<nsIJSON> serializer = do_CreateInstance("@mozilla.org/dom/json;1");
+  if (NS_WARN_IF(!serializer)) {
+    return NS_ERROR_FAILURE;
+  }
+  JS::RootedValue value(aCx, JS::ObjectValue(*aObject));
+  return serializer->EncodeFromJSVal(value.address(), aCx, aSerializedObject);
+}
+
+nsresult
+DeserializeToJSObject(const nsAString& aSerializedObject, JSContext* aCx, JS::MutableHandleObject aObject) {
+  nsCOMPtr<nsIJSON> deserializer = do_CreateInstance("@mozilla.org/dom/json;1");
+  if (NS_WARN_IF(!deserializer)) {
+    return NS_ERROR_FAILURE;
+  }
+  JS::RootedValue value(aCx);
+  JS::MutableHandleValue handleVal(&value);
+  nsresult rv = deserializer->DecodeToJSVal(aSerializedObject, aCx, handleVal);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+  if (value.isObject()) {
+    aObject.set(&value.toObject());
+  } else {
+    aObject.set(nullptr);
+  }
+  return NS_OK;
+}
+
+nsresult
 ConvertStringstoISupportsStrings(const nsTArray<nsString>& aStrings,
                                  nsIArray** aIStrings)
 {
   NS_ENSURE_ARG_POINTER(aIStrings);
   *aIStrings = nullptr;
   nsCOMPtr<nsIMutableArray> iStrings = do_CreateInstance(NS_ARRAY_CONTRACTID);
   for (const nsString& string : aStrings) {
     nsCOMPtr<nsISupportsString> iString =
--- a/dom/payments/PaymentRequestUtils.h
+++ b/dom/payments/PaymentRequestUtils.h
@@ -9,15 +9,25 @@
 
 #include "nsIArray.h"
 #include "nsTArray.h"
 
 namespace mozilla {
 namespace dom {
 
 nsresult
+SerializeFromJSObject(JSContext* aCx,
+                      JS::HandleObject aObject,
+                      nsAString& aSerializedObject);
+
+nsresult
+DeserializeToJSObject(const nsAString& aSerializedObject,
+                      JSContext* aCx,
+                      JS::MutableHandleObject aObject);
+
+nsresult
 ConvertStringstoISupportsStrings(const nsTArray<nsString>& aStrings,
                                  nsIArray** aIStrings);
 
 } // end of namespace dom
 } // end of namespace mozilla
 
 #endif
--- a/dom/payments/PaymentResponse.cpp
+++ b/dom/payments/PaymentResponse.cpp
@@ -1,15 +1,16 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/PaymentResponse.h"
+#include "PaymentRequestUtils.h"
 
 namespace mozilla {
 namespace dom {
 
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(PaymentResponse, mOwner,
                                       mShippingAddress, mPromise)
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(PaymentResponse)
@@ -30,28 +31,26 @@ PaymentResponse::PaymentResponse(nsPIDOM
                                  const nsAString& aPayerName,
                                  const nsAString& aPayerEmail,
                                  const nsAString& aPayerPhone)
   : mOwner(aWindow)
   , mCompleteCalled(false)
   , mInternalId(aInternalId)
   , mRequestId(aRequestId)
   , mMethodName(aMethodName)
+  , mDetails(aDetails)
   , mShippingOption(aShippingOption)
   , mPayerName(aPayerName)
   , mPayerEmail(aPayerEmail)
   , mPayerPhone(aPayerPhone)
   , mShippingAddress(aShippingAddress)
 {
 
   // TODO: from https://github.com/w3c/browser-payment-api/issues/480
   // Add payerGivenName + payerFamilyName to PaymentAddress
-
-  // TODO : need to figure how to deserialize aDetails to JSObject
-
 }
 
 PaymentResponse::~PaymentResponse()
 {
 }
 
 JSObject*
 PaymentResponse::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
@@ -67,19 +66,19 @@ PaymentResponse::GetRequestId(nsString& 
 
 void
 PaymentResponse::GetMethodName(nsString& aRetVal) const
 {
   aRetVal = mMethodName;
 }
 
 void
-PaymentResponse::GetDetails(JSContext* cx, JS::MutableHandle<JSObject*> aRetVal) const
+PaymentResponse::GetDetails(JSContext* aCx, JS::MutableHandle<JSObject*> aRetVal) const
 {
-  // TODO : need to save aDetails as JSObject
+  DeserializeToJSObject(mDetails, aCx, aRetVal);
 }
 
 void
 PaymentResponse::GetShippingOption(nsString& aRetVal) const
 {
   aRetVal = mShippingOption;
 }
 
--- a/dom/payments/PaymentResponse.h
+++ b/dom/payments/PaymentResponse.h
@@ -69,16 +69,17 @@ protected:
   ~PaymentResponse();
 
 private:
   nsCOMPtr<nsPIDOMWindowInner> mOwner;
   bool mCompleteCalled;
   nsString mInternalId;
   nsString mRequestId;
   nsString mMethodName;
+  nsString mDetails;
   nsString mShippingOption;
   nsString mPayerName;
   nsString mPayerEmail;
   nsString mPayerPhone;
   RefPtr<PaymentAddress> mShippingAddress;
   // Promise for "PaymentResponse::Complete"
   RefPtr<Promise> mPromise;
 };
--- a/dom/payments/ipc/PPaymentRequest.ipdl
+++ b/dom/payments/ipc/PPaymentRequest.ipdl
@@ -91,23 +91,30 @@ struct IPCPaymentAbortActionRequest
 };
 
 struct IPCPaymentCompleteActionRequest
 {
   nsString requestId;
   nsString completeStatus;
 };
 
+struct IPCPaymentUpdateActionRequest
+{
+  nsString requestId;
+  IPCPaymentDetails details;
+};
+
 union IPCPaymentActionRequest
 {
   IPCPaymentCreateActionRequest;
   IPCPaymentCanMakeActionRequest;
   IPCPaymentShowActionRequest;
   IPCPaymentAbortActionRequest;
   IPCPaymentCompleteActionRequest;
+  IPCPaymentUpdateActionRequest;
 };
 
 struct IPCPaymentCanMakeActionResponse
 {
   nsString requestId;
   bool result;
 };
 
@@ -137,23 +144,42 @@ struct IPCPaymentCompleteActionResponse
 union IPCPaymentActionResponse
 {
   IPCPaymentCanMakeActionResponse;
   IPCPaymentShowActionResponse;
   IPCPaymentAbortActionResponse;
   IPCPaymentCompleteActionResponse;
 };
 
+struct IPCPaymentAddress
+{
+  nsString country;
+  nsString[] addressLine;
+  nsString region;
+  nsString city;
+  nsString dependentLocality;
+  nsString postalCode;
+  nsString sortingCode;
+  nsString languageCode;
+  nsString organization;
+  nsString recipient;
+  nsString phone;
+};
+
 sync protocol PPaymentRequest
 {
   manager PBrowser;
 
 parent:
   async __delete__();
 
   async RequestPayment(IPCPaymentActionRequest aAction);
 
 child:
   async RespondPayment(IPCPaymentActionResponse aResponse);
+  async ChangeShippingAddress(nsString aRequestId,
+                              IPCPaymentAddress aAddress);
+  async ChangeShippingOption(nsString aRequestId,
+                             nsString aOption);
 };
 
 } // end of namespace dom
 } // end of namespace mozilla
--- a/dom/payments/ipc/PaymentRequestChild.cpp
+++ b/dom/payments/ipc/PaymentRequestChild.cpp
@@ -38,16 +38,48 @@ PaymentRequestChild::RecvRespondPayment(
   MOZ_ASSERT(manager);
   nsresult rv = manager->RespondPayment(response);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return IPC_FAIL_NO_REASON(this);
   }
   return IPC_OK();
 }
 
+mozilla::ipc::IPCResult
+PaymentRequestChild::RecvChangeShippingAddress(const nsString& aRequestId,
+                                               const IPCPaymentAddress& aAddress)
+{
+  if (!mActorAlive) {
+    return IPC_FAIL_NO_REASON(this);
+  }
+  RefPtr<PaymentRequestManager> manager = PaymentRequestManager::GetSingleton();
+  MOZ_ASSERT(manager);
+  nsresult rv = manager->ChangeShippingAddress(aRequestId, aAddress);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return IPC_FAIL_NO_REASON(this);
+  }
+  return IPC_OK();
+}
+
+mozilla::ipc::IPCResult
+PaymentRequestChild::RecvChangeShippingOption(const nsString& aRequestId,
+                                              const nsString& aOption)
+{
+  if (!mActorAlive) {
+    return IPC_FAIL_NO_REASON(this);
+  }
+  RefPtr<PaymentRequestManager> manager = PaymentRequestManager::GetSingleton();
+  MOZ_ASSERT(manager);
+  nsresult rv = manager->ChangeShippingOption(aRequestId, aOption);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return IPC_FAIL_NO_REASON(this);
+  }
+  return IPC_OK();
+}
+
 void
 PaymentRequestChild::ActorDestroy(ActorDestroyReason aWhy)
 {
   mActorAlive = false;
   RefPtr<PaymentRequestManager> manager = PaymentRequestManager::GetSingleton();
   MOZ_ASSERT(manager);
   nsresult rv = manager->ReleasePaymentChild(this);
   if (NS_WARN_IF(NS_FAILED(rv))) {
--- a/dom/payments/ipc/PaymentRequestChild.h
+++ b/dom/payments/ipc/PaymentRequestChild.h
@@ -13,24 +13,34 @@ namespace mozilla {
 namespace dom {
 
 class PaymentRequestChild final : public PPaymentRequestChild
 {
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(PaymentRequestChild);
 public:
   PaymentRequestChild();
 
-  virtual mozilla::ipc::IPCResult
+  void MaybeDelete();
+
+  nsresult RequestPayment(const IPCPaymentActionRequest& aAction);
+
+protected:
+  mozilla::ipc::IPCResult
   RecvRespondPayment(const IPCPaymentActionResponse& aResponse) override;
 
+  mozilla::ipc::IPCResult
+  RecvChangeShippingAddress(const nsString& aRequestId,
+                            const IPCPaymentAddress& aAddress) override;
+
+  mozilla::ipc::IPCResult
+  RecvChangeShippingOption(const nsString& aRequestId,
+                           const nsString& aOption) override;
+
   void ActorDestroy(ActorDestroyReason aWhy) override;
 
-  void MaybeDelete();
-
-  nsresult RequestPayment(const IPCPaymentActionRequest& aAction);
 private:
   ~PaymentRequestChild() = default;
 
   bool SendRequestPayment(const IPCPaymentActionRequest& aAction);
 
   bool mActorAlive;
 };
 
--- a/dom/payments/ipc/PaymentRequestParent.cpp
+++ b/dom/payments/ipc/PaymentRequestParent.cpp
@@ -123,16 +123,34 @@ PaymentRequestParent::RecvRequestPayment
                                        request.completeStatus());
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return IPC_FAIL_NO_REASON(this);
       }
       action = do_QueryInterface(completeAction);
       MOZ_ASSERT(action);
       break;
     }
+    case IPCPaymentActionRequest::TIPCPaymentUpdateActionRequest: {
+      const IPCPaymentUpdateActionRequest& request = aRequest;
+
+      nsCOMPtr<nsIPaymentDetails> details;
+      rv = payments::PaymentDetails::Create(request.details(), getter_AddRefs(details));
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return IPC_FAIL_NO_REASON(this);
+      }
+
+      nsCOMPtr<nsIPaymentUpdateActionRequest> updateAction =
+        do_CreateInstance(NS_PAYMENT_UPDATE_ACTION_REQUEST_CONTRACT_ID);
+      rv = updateAction->InitRequest(request.requestId(),
+                                     callback,
+                                     details);
+      action = do_QueryInterface(updateAction);
+      MOZ_ASSERT(action);
+      break;
+    }
     default: {
       return IPC_FAIL(this, "Unexpected request type");
     }
   }
   nsCOMPtr<nsIPaymentRequestService> service =
     do_GetService(NS_PAYMENT_REQUEST_SERVICE_CONTRACT_ID);
   MOZ_ASSERT(service);
   rv = service->RequestPayment(action);
@@ -234,16 +252,126 @@ PaymentRequestParent::RespondPayment(nsI
     }
     default: {
       return NS_ERROR_FAILURE;
     }
   }
   return NS_OK;
 }
 
+NS_IMETHODIMP
+PaymentRequestParent::ChangeShippingAddress(const nsAString& aRequestId,
+                                            nsIPaymentAddress* aAddress)
+{
+  if (!NS_IsMainThread()) {
+    nsCOMPtr<nsIPaymentActionCallback> self = this;
+    nsCOMPtr<nsIPaymentAddress> address = aAddress;
+    nsAutoString requestId(aRequestId);
+    nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction([self, requestId, address] ()
+    {
+      self->ChangeShippingAddress(requestId, address);
+    });
+    return NS_DispatchToMainThread(r);
+  }
+  if (!mActorAlived) {
+    return NS_ERROR_FAILURE;
+  }
+  nsAutoString country;
+  nsresult rv = aAddress->GetCountry(country);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsCOMPtr<nsIArray> iaddressLine;
+  rv = aAddress->GetAddressLine(getter_AddRefs(iaddressLine));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsAutoString region;
+  rv = aAddress->GetRegion(region);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsAutoString city;
+  rv = aAddress->GetCity(city);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsAutoString dependentLocality;
+  rv = aAddress->GetDependentLocality(dependentLocality);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsAutoString postalCode;
+  rv = aAddress->GetPostalCode(postalCode);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsAutoString sortingCode;
+  rv = aAddress->GetSortingCode(sortingCode);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsAutoString languageCode;
+  rv = aAddress->GetLanguageCode(languageCode);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsAutoString organization;
+  rv = aAddress->GetOrganization(organization);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsAutoString recipient;
+  rv = aAddress->GetRecipient(recipient);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsAutoString phone;
+  rv = aAddress->GetPhone(phone);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsTArray<nsString> addressLine;
+  uint32_t length;
+  rv = iaddressLine->GetLength(&length);
+  NS_ENSURE_SUCCESS(rv, rv);
+  for (uint32_t index = 0; index < length; ++index) {
+    nsCOMPtr<nsISupportsString> iaddress = do_QueryElementAt(iaddressLine, index);
+    MOZ_ASSERT(iaddress);
+    nsAutoString address;
+    rv = iaddress->GetData(address);
+    NS_ENSURE_SUCCESS(rv, rv);
+    addressLine.AppendElement(address);
+  }
+
+  IPCPaymentAddress ipcAddress(country, addressLine, region, city,
+                               dependentLocality, postalCode, sortingCode,
+                               languageCode, organization, recipient, phone);
+
+  nsAutoString requestId(aRequestId);
+  if (!SendChangeShippingAddress(requestId, ipcAddress)) {
+    return NS_ERROR_FAILURE;
+  }
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentRequestParent::ChangeShippingOption(const nsAString& aRequestId,
+                                           const nsAString& aOption)
+{
+  if (!NS_IsMainThread()) {
+    nsCOMPtr<nsIPaymentActionCallback> self = this;
+    nsAutoString requestId(aRequestId);
+    nsAutoString option(aOption);
+    nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction([self, requestId, option] ()
+    {
+      self->ChangeShippingOption(requestId, option);
+    });
+    return NS_DispatchToMainThread(r);
+  }
+  if (!mActorAlived) {
+    return NS_ERROR_FAILURE;
+  }
+  nsAutoString requestId(aRequestId);
+  nsAutoString option(aOption);
+  if (!SendChangeShippingOption(requestId, option)) {
+    return NS_ERROR_FAILURE;
+  }
+  return NS_OK;
+}
+
 mozilla::ipc::IPCResult
 PaymentRequestParent::Recv__delete__()
 {
   mActorAlived = false;
   return IPC_OK();
 }
 
 void
--- a/dom/payments/moz.build
+++ b/dom/payments/moz.build
@@ -12,28 +12,30 @@ EXPORTS += [
     'PaymentRequestData.h',
     'PaymentRequestService.h',
 ]
 
 EXPORTS.mozilla.dom += [
     'PaymentAddress.h',
     'PaymentRequest.h',
     'PaymentRequestManager.h',
+    'PaymentRequestUpdateEvent.h',
     'PaymentResponse.h',
 ]
 
 UNIFIED_SOURCES += [
     'PaymentActionRequest.cpp',
     'PaymentActionResponse.cpp',
     'PaymentAddress.cpp',
     'PaymentRequest.cpp',
     'PaymentRequestData.cpp',
     'PaymentRequestManager.cpp',
     'PaymentRequestModule.cpp',
     'PaymentRequestService.cpp',
+    'PaymentRequestUpdateEvent.cpp',
     'PaymentRequestUtils.cpp',
     'PaymentResponse.cpp',
 ]
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 FINAL_LIBRARY = 'xul'
 
new file mode 100644
--- /dev/null
+++ b/dom/webidl/PaymentRequestUpdateEvent.webidl
@@ -0,0 +1,25 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * The origin of this WebIDL file is
+ *   https://www.w3.org/TR/payment-request/#paymentrequestupdateevent-interface
+ */
+
+dictionary PaymentDetailsUpdate : PaymentDetailsBase {
+  DOMString   error;
+  PaymentItem total;
+};
+
+[Constructor(DOMString type,
+             optional PaymentRequestUpdateEventInit eventInitDict),
+ SecureContext,
+ Func="mozilla::dom::PaymentRequest::PrefEnabled"]
+interface PaymentRequestUpdateEvent : Event {
+  [Throws]
+  void updateWith(Promise<PaymentDetailsUpdate> detailsPromise);
+};
+
+dictionary PaymentRequestUpdateEventInit : EventInit {
+};
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -721,16 +721,17 @@ WEBIDL_FILES = [
     'OscillatorNode.webidl',
     'PaintRequest.webidl',
     'PaintRequestList.webidl',
     'PaintWorkletGlobalScope.webidl',
     'PannerNode.webidl',
     'ParentNode.webidl',
     'PaymentAddress.webidl',
     'PaymentRequest.webidl',
+    'PaymentRequestUpdateEvent.webidl',
     'PaymentResponse.webidl',
     'Performance.webidl',
     'PerformanceEntry.webidl',
     'PerformanceMark.webidl',
     'PerformanceMeasure.webidl',
     'PerformanceNavigation.webidl',
     'PerformanceObserver.webidl',
     'PerformanceObserverEntryList.webidl',