-
Notifications
You must be signed in to change notification settings - Fork 217
CAIP-358: Universal Payment Request Method #358
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
pedrouid
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks awesome! Exactly in line with the feedback that I've been receiving 👌
Using this standard we could easily create a universal standard for "Pay with Ethereum" or "Pay with Solana".... and of course.... WalletConnect would offer this as part of the Network!
|
This seems quite focused on URL specifics for mobile app wallets. We likely need to address both mobile and desktop browser implementations too. For example, within brave browser on mobile the user can interact with it using the same interface that's used by an extension on a desktop. If we only focus on the QR code scanning interaction, we'll lose support for this when people are on desktop browser (or in limited circumstances, browsing on a wallet's WebView or relying on Brave's mobile wallet implementation). This is one of the reasons I was looking towards a JSON-RPC that can be included in a specific script, and done so in a way that has it's agnostic wallet object for this. For example, |
|
Also as a side note, would you prefer that I publish my draft document or offer a PR onto yours so that we can account for it? We'll likely need both interactions to seamless make this work across platforms and interactions. |
|
Would it be a good idea to align the API to |
|
@jxom Great idea! Makes a lot of sense IMO |
|
@kdenhartog I don't think this only focuses on the QR code scan. It defines the RPC but not the method of transfer. It can be via the QR Code (WalletConnect) or via the provider. I think it can work quite well for the browser extension wallets. I'll create a discussion and we can follow up there |
|
@kdenhartog Discussion: #359 |
| data?: any; | ||
| } | ||
| ``` | ||
| The wallet **MUST** use one of the following error codes when the pay request fails: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
might it be more future-proof to require an error message 800X or 80XX, or is the idea specifically that these are the only 4 valid errors to throw?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In this version, there are. If there are other errors, or different use cases someone can write a new CAIP
|
|
||
| ## Test Cases | ||
| <!--Please add diverse test cases here if applicable. Any normative definition of an interface requires test cases to be implementable. --> | ||
| TODO |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would recommend adding both positive and negative cases here, it never hurts! it might also be a good place to stick end-to-end examples showing how it can be combined with x402, caip-25, wallet-standard, etc (i.e. end-to-end examples showing other layers, not just payment requests).
What does this mean, concretely? does this mean renaming |
It means exposing the interface (and possibly a lot of the spec itself!) to Wallets, and not just Browsers. Deduping and not reinventing too much would be ideal, as I see this spec having nearly identical intention. |
Am I understanding properly that you want to polyfill on this? I think if we do this we're going to walk back into the 6963 problem where multiple extensions will polyfill ontop of this. This is one of the issues that's plagued passkeys too is that multiple providers want to participate in the flow (extensions/browsers/OS). While I'm a fan of mapping the logic to what they've already got, I'm a bit concerned about reintroducing these issues we just solved. Also, there is a possibility for a browser to just prevent overrides of the scripts they inject into the page, so we may want to be careful here such that wallets' participation in this flow don't get consumed by the underlying browser implementation. Brave specifically has taken the stance we won't do this and have settings to allow the user to override it. However, hearing what happened during the first go with PaymentRequest API (plus hardly ever seeing it used) I'm cautious about how others may participate since core business revenues are often built on capturing these flows and the data that's passed in it. In laying out all my cautions now, I will say I'm actually quite supportive of this direction if we can figure out how to make it work. This seems like a good way to adversarial interop on it and pick up adoption from the limited use of it so far. |
|
No, I purely mean just aligning the interface that can be used in the |
xzilja
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great proposal 👌 left some suggestions
| type PayRequest = { | ||
| orderId: string; | ||
| acceptedPayments: PaymentOption[]; | ||
| expiry: number; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it be useful to also add an optional, human readable identifier like label / description here? Something similar to Solana Pay to help user identify payment request. Perhaps multiple of these can come through when they open up a wallet or come back online etc.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed. Solana Pay includes the following which are not specified here but have had proven use:
- Label: UTF-8 string that describes the source of the transfer request (ex: a brand, store, app etc)
- Message: UTF-8 string that is user facing to describe the nature of the request. This can help add context to wallets who display this request.
- Memo: similar to the orderId above but more broad in specification
Additionally, on Solana you can embed arbitrary public keys in the message to allow for easy tracking or reference. This is the "reference" field and is extremely helpful for wallets/apps to be able to track client IDs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Have there been instances of this data being fraudulently submitted by a scam site for the purposes of tricking the user? It seems like due to instant settlements of crypto payments, there's more risk to submitting these payments to untrusted sites that have no intention of shipping goods or services once they receive payment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm sure there have been instances.. it's crypto so scams are bound to happen. I think we can fix this by having some sort of tls-like auth mechanism, or perhaps an integrity signature. I'm not sure if this would be defined in this caip or at a protocol level or as an additional capability to be adopted by teams where it makes sense
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My $0.02: there's not just scams in the form of "this data being fraudulently submitted by a scam site for the purposes of tricking the user" but there's also the problem of "fake stores" selling you iPhones that don't exist.
I believe trying to accomplish this with wallet_pay in its initial form is too much. But in a future iteration or addendum the problem of merchant fraud insurance must be covered.
FWIW: if wallet_pay is transmitted via WalletConnect then the transport provides some scam protection via WalletConnects "Verify API"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with @arein
This should definitely be left out. By default wallet would be unable to display untrusted information, or at least it should never do that.
CAIPs/caip-358.md
Outdated
| <!--Please add diverse test cases here if applicable. Any normative definition of an interface requires test cases to be implementable. --> | ||
| TODO | ||
| ## Security Considerations | ||
| <!--Please add an explicit list of intra-actor assumptions and known risk factors if applicable. Any normative definition of an interface requires these to be implementable; assumptions and risks should be at both individual interaction/use-case scale and systemically, should the interface specified gain ecosystem-namespace adoption. --> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If possible, should provide a verifiable source of payment request i.e dapp domain
|
|
||
| type PaymentOption = { | ||
| asset: string; | ||
| amount: Hex; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am rusty on this, but does amount need to be a Hex, or can it be a simpler string like "100.0"? Is it common for non-evm wallets to use hex's here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think hex is a pretty good convention. If you put "100.0" then everyone has to do the conversion. Pretty much all downstream RPCs and SDKs accept hex
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
btw hex is extremely not standard in Solana
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can consider uint
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't think we need to overthink it. Hex is a universal convention beyond crypto applications (ie. JS 0x69 resolves to 105 as a number, and we are referring to a JSON-RPC interface here) for numbers exceeding Number.MAX_SAFE_INTEGER.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since this is something that's going to be interpreted by the wallet is there a reason to not just go with JSON number? Seems like then it just becomes the wallets responsibility to format it correctly for the particular chain in the transaction. In this way language specific aspects around types (e.g. some need doubles, floats, uints, etc) also become simpler too.
CAIPs/caip-358.md
Outdated
| "amount": "0x5F5E100" | ||
| }, | ||
| { | ||
| "recipient": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp:9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: historically we have recommended using the solana genesis hash as the "chain id". As is this would not allow for disambiguation between mainnet and devnet for example
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@gitteri Are you referring to https://chainagnostic.org/CAIPs/caip-30?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Didn't know this exists but yes
| The `wallet_pay` method **MUST** be idempotent for the same `orderId`. This ensures robustness in case of connection failures or timeout scenarios. | ||
|
|
||
| Requirements: | ||
| - If a payment with the same `orderId` has already been completed successfully, the wallet **MUST** return the original `PayResult` without executing a new payment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add more details as to the unique constraints for the orderId? is this per merchant app? Many chains don't have the ability to embed orderIds onchain so this information is likely held offchain.
On Solana, it's common to use the memo + reference key to uniquely identify the transaction as this data is onchain
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The orderId doesn't have to be stored onchain. It should be unique for each order. Merchant generated UUID should work just fine
To start, I agree this makes the most sense. You're going to hate me here though... but I want to expose this only with the 282 work so that we have an actually chain agnostic approach here. For example, it would be odd to call the following through The reason I'm suggesting that though is because we're now at the point where we've got |
It's good that we agree there! I was only concerned about the interface part, not the transport part. From my understanding, this spec outlines a JSON-RPC format and the behavior of it, but not the underlying transport itself. Is it right to assume that this can be plugged into any JSON-RPC compatible transport? Whether it be EIP-6963, CAIP-282, |
@jxom You're exactly right. The spec intentionally doesn't define the transport layer, and any one of those you mentioned can be used. |
|
@jxom that's a great clarifying question. I hadn't reached the conclusion until we discussed further on the separate discussion. Ok, cool sounds like we're all on the same page for that then because that was what I was expecting too. I think the other thing that might need to be defined is how the RPC request data can encoded into a URI that can be fired and forgotten. Then the recipient would poll the chain for data round it or potentially make a callback to a webhook or something. This way we can make payment requests with the same format over QR codes/NFC/deeplinks/etc The question I'd have for you @lukaisailovic is would this be better defined within the scope of this spec or better done as a separate spec? |
|
Also, I can open a PR onto |
|
@kdenhartog URI encoding + webhook is significantly more complex, primarily for dapps who now need a backend to check payment status, but for the wallet as well. I specifically wanted to avoid that approach as this is much lower lift to implement. I'd prefer to leave it out of this spec, and if someone wants to do that, they can create a new spec and define exactly how that should be handled. Additionally the same method can be transmitted via NFC if someone defines that as a universal transport for RPCs. TLDR Different spec for general transport is better IMO. No need to couple things unnecessarily |
|
@lukaisailovic nice proposal! curious if you've considered a path where this use case could be handled as elegantly using EIP-5792. happy to provide more feedback on this API specifically, but i just wonder if we'd have more impact overall by leveraging momentum the space already has with for reference, Coinbase is also working on this feature: https://docs.base.org/identity/smart-wallet/guides/profiles#profiles , which uses EIP-5792 and could serve things like express checkout well. so im curious if there's some middle ground to be found here |
CAIPs/caip-358.md
Outdated
|
|
||
| // JSON-RPC Request | ||
| type PayRequest = { | ||
| orderId: string; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wondering if this should by inside of a good old context field. curious if you think this could be used for p2p use cases too, where there might not really be a meaningful orderId
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
++ to making this optional. One of the cases I think we may be interested in this for eventually would be for P2P creator tipping in Brave Rewards.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, we can make it optional.
@lukasrosario currently its the only property, but if we wanted to future proof it it might make sense
|
@lukasrosario EIP-5792 is EVM specific in it's design whereas this is intended to be a chain agnostic design. Additionally, EIP-5792 is a low level RPC call that presumes a DApp has requested access to the account address and will format the transaction. This takes a different approach aiming for it to be a high level RPC API that doesn't require a connection for the page to engage with the RPC. The advantage here is that the wallet can receive payment requests without a connection request in the first place. It simply detects the wallet via a channel like EIP-6963/CAIP-282 then submits a request and the wallet handles the rest. The advantage here is that, it reduces the complexity on the site developer to not need to understand how to formulate a transaction specific to the blockchain in use or being bridged to. With that in mind, I'd expect the wallet may use EIP-5792 transaction bundles when interacting with EVM chains rather than discrete transactions in order to avoid high latency, but this is an implementation choice of each wallet so would remain out of scope. |
FWIW, ERC-5792 does not require a connection either ( |
|
TIL, thanks for the correction @jxom. In any case, I do think it still introduces too much complexity to the site for this specific case, because they need to know which protocols to interact with and their calldata formats, but in general I do think it fits in well as a powerful low level primitive that sits next to this. |
|
|
||
| This multi-step process creates excessive friction, often requiring 4-6 user interactions for a simple payment. | ||
|
|
||
| The `wallet_pay` method addresses these limitations by: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for consideration: EIP-681 and Solana Pay are similar but chain specific. In order to remove chain selection on the PSP level it has to be chain agnostic by design
| } | ||
| ``` | ||
|
|
||
| ## Rationale |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should something about supporting Smart Contract payment flavors like Coinbase Commerce be added here?
Also should the be a discussion somewhere in the CAIP on how developers can reconcile payments? What happens when the wallet can send the transaction but then the internet cuts off and the user can no longer switch back to the dapp?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I actually removed smart contract interactions. It adds too much complexity for not a lot of benefits.
Currently the only reason its used is to identify payments, which can be done differently in a more efficient way. Also some implementations still use contracts with direct deposit into them
| type PayRequest = { | ||
| orderId: string; | ||
| acceptedPayments: PaymentOption[]; | ||
| expiry: number; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My $0.02: there's not just scams in the form of "this data being fraudulently submitted by a scam site for the purposes of tricking the user" but there's also the problem of "fake stores" selling you iPhones that don't exist.
I believe trying to accomplish this with wallet_pay in its initial form is too much. But in a future iteration or addendum the problem of merchant fraud insurance must be covered.
FWIW: if wallet_pay is transmitted via WalletConnect then the transport provides some scam protection via WalletConnects "Verify API"
CAIPs/caip-358.md
Outdated
| ```json | ||
| { | ||
| "orderId": "order-123456", | ||
| "acceptedPayments": [ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This may be for another CAIP or even controversial, but with stablecoin proliferation, merchants will soon accept dozens of different stablecoins while only caring about the underlying value (e.g., USD). Moreover, users often hold multiple USD stablecoins across different chains and should be able to use any of them when paying in USD, rather than having to choose a specific implementation. This also applies to other asset equivalents like BTC and wrapped BTC variants.
Adding a grouping or equivalency concept to the payment options where assets with the same underlying value can be grouped together would let wallets show "Pay $100 in USD" where users can either pick a specific asset or let the wallet automatically select the best option (lowest fees, available balance) instead of forcing them to pick between USDC on Ethereum vs Polygon vs Solana when they just want to pay in dollars.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems worth exploring what works better here through implementation experimentation a bit more. When I was thinking about this, I was somewhat expecting that would be the case for the most part anyways, but through implementation specific wallet UX, so that we can optimize on this overtime. What I originally had in mind was that the wallet operates on the following heuristic:
- Check which currencies the recipient wants and which are available without a swap/bridge
- If payment can be handled with currently available funds, offer that first. It's almost certainly lowest in terms of fees, but this is an assumption that may be invalidated as networks and swap/bridge protocols compete for lower fees.
- If swap/bridge is necessary, check which current currencies the user holds can cover funds. Also, determine which of the currencies the recipient wants to have the most liquidity.
- Then get a swap/bridge quote from users current funds that can cover for each pair of users funds and the most liquid stablecoin chosen.
- Display these options to the user from least to most fees, with the default being least.
Additionally, allow the user to override as necessary in optional transaction panel, in case they don't want to use a particular fund. I think Users will demand what sort of UX they want here too, so we can optimize a bit further as the feature becomes available, without needing to change the RPC data model. That should remain our top priority here IMO.
From the merchant's perspective, one of the issues we've found with spending/receiving funds today with BAT and rewards ads is that there's a constant need to bridge/swap funds and in some cases off-ramp back to fiat (hopefully that's not a problem of the future). This can be a bit of a headache for accounting/tax purposes on the merchant side. So, part of the advantage to the recipient specifying network/currency exactly is that it makes merchant onboarding a bit easier in terms of fund management which makes it more likely that Metcalfe's law kicks in here. E.g. they can always have USDC on their network of choice and easily offramp that as needed to pay their invoices/employees. Additionally, since most wallets universally have some form of swap/bridge functionality I don't think it's going to be overly difficult for us to swap/bridge as needed and handle the complexity for the user. This also means we'll be able to easily handle currency conversion via stablecoins using the same heuristic too.
I may be making some incorrect assumptions here though, so thank you for calling this out. Ultimately, whatever the implementation feedback and early testing with users/merchants tells us here is going to be the decider IMO.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Adding a grouping or equivalency concept to the payment options where assets with the same underlying value can be grouped together would let wallets show "Pay $100 in USD"
@argjv Agreed that this requires orthogonal/separate specification, whether as another CAIP or outside of CASA. Still going to chime in here because I used to work at Circle and am fascinated personally by the topic-- tag me if this is proposed somewhere else as a spec!
Upfront I would just say that $100 in USDC (on any chain/in any formfactor) is an abstraction that makes sense to me (cf. Layer Zero and Circle's devrel strategy), but $100 in "any stablecoin" is a non-starter IMHO: not just because some people have hard regulatory requirements to use, e.g. Circle but not Tether, or Paxos but not Luna/GUSD/etc etc, but ALSO because their "semantic equivalence" is just not deliverable in practice given the way DEXs and solvers and bridges are incentivized by their contracts, API billing structures, and the terms of their integrations deals to favor one over the other and devoid "de minimis" monthly transaction volumes in any other stables...
What I could see happening is USDC and comparable-regulated stablecoins federating to create one broader meta-coin, e.g. "USDC+", which would abstract over and translate between USDC on any chain, Paxos on any chain, etc etc.
Co-authored-by: Derek <alexanderderekrein@gmail.com> Co-authored-by: Bumblefudge <bumblefudge@learningproof.xyz>
|
|
||
| Requirements: | ||
| - If a payment with the same `orderId` has already been completed successfully, the wallet **MUST** return the original `PayResult` without executing a new payment | ||
| - If a payment with the same `orderId` is currently pending, the wallet **SHOULD** return the result of the original payment attempt |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just to clarify. What's the result of the original payment attempt? If the payment is currently pending the result is not yet available
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the wallet returned txid and you submit the payment with the same orderId, the same txid will be returned. The result doesn't specify the tx state (pending/success)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With that in mind, it would likely be useful to the site to be able to reliably use this. Otherwise it could potentially lead to a UX divergence where a wallet that doesn't support this re-prompts for a new payment where as a wallet that does respond automatically with the TxID without a user interaction.
Therefore, I think we should upgrade this to a MUST rather than a SHOULD. Is there some reason you went with SHOULD here instead?
|
|
||
| - An `orderId` that uniquely identifies this payment request. If provided, `orderId` **MUST NOT** be longer than 128 characters. | ||
|
|
||
| When `orderId` is provided, it **MUST** be a string and implementations **SHOULD** ensure this ID is unique across their system to prevent collisions. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
would it make more sense to require (or at least recommend) a UUID full-stop? human-readable or monotonic orderIds seem like they would wreak havok since it's not just "across their own system" that collisions could create problems (for, e.g., indexers)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think recommendation is fine, but I don't think it should be a requirement. This is dapp <> wallet RPC, so the orderId is not stored anywhere onchain
| - The `recipient` field **MUST** be a valid [CAIP-10][] account ID. | ||
| - The `asset` field **MUST** follow the [CAIP-19][] standard. | ||
| - The `amount` field **MUST** be a hex-encoded string representing the amount of the asset to be transferred. | ||
| - The [CAIP-2][] chainId component in the [CAIP-19][] `asset` field **MUST** match the [CAIP-2][] chainId component of the [CAIP-10][] `recipient` account ID. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what about the [CAIP-107][] namespace component? 😏
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wdym? chainId is namespace + reference (blockchain Id). Do you mean asset namespace in caip-19? That can't be used for anything, not sure why should we compare it to CAIP-2
| - The `amount` field **MUST** be a hex-encoded string representing the amount of the asset to be transferred. | ||
| - The [CAIP-2][] chainId component in the [CAIP-19][] `asset` field **MUST** match the [CAIP-2][] chainId component of the [CAIP-10][] `recipient` account ID. | ||
|
|
||
| The `expiry` field **MUST** be a UNIX timestamp (in seconds) after which the payment request is considered expired. Wallets **SHOULD** check this timestamp before processing the payment. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| The `expiry` field **MUST** be a UNIX timestamp (in seconds) after which the payment request is considered expired. Wallets **SHOULD** check this timestamp before processing the payment. | |
| The `expiry` field **MUST** be a UNIX timestamp (in seconds) after which the payment request is considered expired. Wallets **SHOULD** check this timestamp is not in the past before proposing or submitting a payment. |
| When `orderId` is not provided: | ||
|
|
||
| - Each payment request **SHOULD** be treated as a new payment attempt | ||
| - Wallets **MAY** implement their own deduplication logic based on other request parameters (recipient, asset, amount, expiry) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| - Wallets **MAY** implement their own deduplication logic based on other request parameters (recipient, asset, amount, expiry) | |
| - Wallets **MAY**, however, implement their own deduplication logic based on other request parameters (recipient, asset, amount, expiry) to prevent unintended duplicate payments for identical requests |
bumblefudge
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is complete enough to publish as a draft, but i'd love to see test cases long before last call if possible, to help along alternate implementations
|
From today's WC UX Council meeting discussion of CAIP-358:
|
++ I think it makes sense for us to get the draft in and then we can iterate as necessary from here |
kdenhartog
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is more than ready to merge in a draft state. We can iterate as we go from here
|
@bumblefudge I think you guys have to merge it right? |
This CAIP standardizes a
wallet_payJSON-RPC method enabling one-click cryptocurrency payments across wallets and dapps. Allows merchants to specify multiple payment options (cross-chain assets) in a single request, letting wallets automatically select the optimal payment method based on user's available assets. Eliminates the current multi-step payment flow (select token → select chain → generate address → manual transfer) by moving payment choice and execution to the wallet, reducing friction from 4-6 clicks to a single interaction.