-
Notifications
You must be signed in to change notification settings - Fork 493
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
Add ERC: Tap to Pay #686
base: master
Are you sure you want to change the base?
Add ERC: Tap to Pay #686
Changes from all commits
2a53c86
96d6ac6
98f6b9d
1d625b6
c498382
1374d1a
768b114
bcc7b4c
62a5e7e
b0b33c8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,200 @@ | ||||||
--- | ||||||
eip: 7798 | ||||||
title: Tap to Pay | ||||||
description: Initializing contactless payment transactions from EVM wallets | ||||||
author: Amhed Herrera (@amhed), Justin Lee (@JustinDLee), Arjun Dureja (@arjun-dureja) | ||||||
discussions-to: https://ethereum-magicians.org/t/erc-7798-contactless-payment/21501 | ||||||
status: Draft | ||||||
type: Standards Track | ||||||
category: ERC | ||||||
created: 2024-10-25 | ||||||
requires: 20, 681, 712 | ||||||
--- | ||||||
|
||||||
## Abstract | ||||||
This ERC defines a standard for contactless payment transactions that can allow for interoperable customer to merchant onchain payments, regardless of the wallets the customer and merchant are using. | ||||||
|
||||||
## Motivation | ||||||
Currently there is no standard mechanism in crypto to do contactless payment transactions via NFC. This ERC defines a standardized way of exchanging payment information between merchants and customers, or peer-to-peer individuals, so that efficient checkout can occur. | ||||||
|
||||||
## Specification | ||||||
|
||||||
Comprised of three parts: | ||||||
- A new Ethereum Provider JavaScript API method called `requestContactlessPayment` | ||||||
- An agreement on the payload for data exchange between the parties | ||||||
- An optional mechanism for relaying large JSON payloads using a backend relayer | ||||||
|
||||||
|
||||||
```mermaid | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Our renderer doesn't support mermaid. Please replace it with an image in your assets directory (preferably an SVG.) |
||||||
sequenceDiagram | ||||||
Sender->>PoS: Generate checkout intent | ||||||
PoS->>NFC Relayer: Upload checkout intent JSON | ||||||
PoS->>JSON RPC: requestContactlessPayment(uuid) | ||||||
JSON RPC->>Wallet: Trigger NFC HCE | ||||||
Recipient->>Wallet: Scan NFC Tag | ||||||
Wallet->>Recipient: Checkout Intent URI | ||||||
Recipient->>NFC Relayer: requestPaymentParams | ||||||
NFC Relayer->>Recipient: Transaction data | ||||||
Recipient->>Recipient: signTransaction | ||||||
Recipient->>RPC Proxy: submitTransaction | ||||||
``` | ||||||
|
||||||
|
||||||
### Use Cases | ||||||
|
||||||
#### Use Case 1: Customer purchases from a merchant | ||||||
1. A customer approaches a merchant and orders an item at their cash register (e.g. a cup of coffee). | ||||||
1. The merchant is running an app on their point-of-sale (PoS) system that allows initiating a checkout flow. | ||||||
1. When the customer is done ordering, the merchant goes through the checkout flow up and triggers a payment request. | ||||||
1. The merchant app calls the `requestContactlessPayment` RPC method with the expected payload. | ||||||
1. The merchant's device emits an NFC signal via host card emulation (HCE) for the customer’s device to read. | ||||||
1. The customer, running their wallet software of choice, reads the NFC signal. The customer’s wallet constructs the necessary transaction(s) to execute the onchain checkout. | ||||||
1. The wallet then signs and submits all transactions. | ||||||
1. Upon successful onchain execution of these transactions, the checkout is complete. | ||||||
|
||||||
#### Use Case 2: Peer-to-peer Sends | ||||||
1. Alice requests a payment on her wallet app by emitting an NFC signal. The contents of the signal is an [ERC-681](erc-681.md) URI | ||||||
> []will this only work with 681? 681 has limitations, like receiver intent which would be great to solve too. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
If you use HTML-style comments, the linter will make sure you replace them before going into Review. |
||||||
|
||||||
1. [ERC-681](erc-681.md) URI Bob reads the NFC signal from Alice on his wallet app and constructs the transaction | ||||||
2. Bob holds his phone close to Alice's which triggers the NFC flow. | ||||||
1. Bob then signs and submits the transaction onchain. | ||||||
1. Send flow is complete. | ||||||
|
||||||
### requestContactlessPayment | ||||||
The requestContactlessPayment method will be added as a standard method to the [EIP-1193 Ethereum Provider JavaScript API](eip-1193). | ||||||
|
||||||
This method takes in two parameters: `type` and `uri`. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I usually recommend including a JSON Schema for any new API endpoints. |
||||||
|
||||||
- `type` is an enum that represents the payload type: | ||||||
- 1 means the URI is an ERC-681-compliant payload. | ||||||
- 2 means the URI points to an HTTP relayer, where the response of the relayer is either a JSON object with the transaction data already encoded as a 0x string, or a message for the customer to sign. The customer wallet is responsible for constructing, signing and submitting the transaction/message. | ||||||
|
||||||
- `uri` represents either the ERC-681-compliant payload or the relayer endpoint to query for the JSON payload. | ||||||
|
||||||
Example calls: | ||||||
|
||||||
```js | ||||||
window.ethereum.request({ | ||||||
method: 'requestContactlessPayment', | ||||||
params: { | ||||||
type: 1, | ||||||
uri: "ethereum:0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913@8453/transfer?address=0xf7d07Ee99095FDC09001710Ec232162a788BB989&uint256=1e5", | ||||||
}); | ||||||
|
||||||
window.ethereum.request({ | ||||||
method: 'requestContactlessPayment', | ||||||
params: { | ||||||
type: 2, | ||||||
uri: "https://nfcrelay.xyz/paymentTxParams?uuid=1234-abcd-56678", | ||||||
verificationCode: "1234567890" | ||||||
} | ||||||
}); | ||||||
``` | ||||||
|
||||||
### Type 1 | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. are offchain signatures supported for type 1? i dont think it's covered by 681? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No, we covered them with the relayed URI. You can basically pass down any long-form payload / set of batched transactions for EIP-3009 or permit2 |
||||||
|
||||||
The transaction is a regular crypto send. The receiving party transmits the [ERC-681](erc-681.md) URI to the sender’s wallet. | ||||||
|
||||||
|
||||||
### Type 2 | ||||||
|
||||||
Handles cases where the payload necessary to construct, sign, and submit the transaction needed for payment is too large to emit over NFC. The intended flow is as follows: | ||||||
|
||||||
1. The merchant dapp makes a POST request to an NFC relayer endpoint with the information needed for completing a sale. | ||||||
1. The merchant’s device then transmits the NFC relayer endpoint URI and verification code to the customer via any means | ||||||
1. The customer’s device then makes a GET request to the endpoint URI | ||||||
|
||||||
One of three payloads can be returned from the NFC relayer: | ||||||
|
||||||
**Regular Send** | ||||||
```ts | ||||||
{ | ||||||
payloadType: 'eip681'; | ||||||
chainId: string; | ||||||
contractAddress: string; | ||||||
toAddress: string; | ||||||
value: string; | ||||||
dappUrl?: string; | ||||||
dappName?: string; | ||||||
rpcProxySubmissionParams?: { | ||||||
submissionUrl?: string; | ||||||
} | ||||||
} | ||||||
``` | ||||||
|
||||||
**Contract Call** | ||||||
|
||||||
```ts | ||||||
{ | ||||||
payloadType: 'contractCall'; | ||||||
chainId: string; | ||||||
approveTxs?: { | ||||||
data: string; // this represents the approval call data | ||||||
toAddress: string; // the address to submit the approve transaction to | ||||||
}[], | ||||||
paymentTx: { | ||||||
data: string; // call data of the transaction, only needed for | ||||||
toAddress: string; // the address to submit the payment transaction to | ||||||
value: string; // the value of the blockchain's native token to transfer over | ||||||
}, | ||||||
rpcProxySubmissionParams?: { | ||||||
submissionUrl?: string; // optional endpoint to submit the tx hash to | ||||||
}, | ||||||
dappUrl?: string; | ||||||
dappName?: string; | ||||||
} | ||||||
``` | ||||||
|
||||||
**[EIP-712](https://eips.ethereum.org/EIPS/eip-712) Message (offline signature)** | ||||||
Check failure on line 149 in ERCS/erc-7798.md GitHub Actions / EIP Walidatornon-relative link or image
Check failure on line 149 in ERCS/erc-7798.md GitHub Actions / EIP Walidatornon-relative link or image
Check failure on line 149 in ERCS/erc-7798.md GitHub Actions / EIP Walidatornon-relative link or image
|
||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. hm i guess sendCalls wouldnt work for getting offchain signatures |
||||||
|
||||||
```ts | ||||||
{ | ||||||
payloadType: 'eip712'; | ||||||
chainId: string, | ||||||
rpcProxySubmissionParams: { | ||||||
submissionUrl: string; // endpoint to submit tx message + signature to | ||||||
typedData: { | ||||||
types: { | ||||||
// any types can go here in accordance with EIP-712 and eth_signtypeddata_v4, it's recommended that every type needed for | ||||||
// generating the right transactions on the RPC proxy is here | ||||||
}, | ||||||
primaryType?: string; | ||||||
domain: { | ||||||
// any domain fields go here, usually need name, version, chainId and verifyingContract | ||||||
}, | ||||||
message: { | ||||||
// any fields can go here, it's recommended that every field needed for | ||||||
// generating the right transactions on the RPC proxy is here | ||||||
} | ||||||
}, | ||||||
}, | ||||||
dappUrl?: string; | ||||||
dappName?: string; | ||||||
additionalPayload?: { | ||||||
// ... any fields can go here, this is additional payload the RPC proxy may need but does not have to bee signed in the message | ||||||
} | ||||||
} | ||||||
``` | ||||||
Upon submitting the transaction for the [ERC-681](erc-681.md) and contract call cases, if `rpcProxySubmissionParams` is present, then the transaction hash can be optionally submitted via a POST request to the submission URL. The body of the POST would have the following structure: | ||||||
```ts | ||||||
{ | ||||||
txHash: string; | ||||||
} | ||||||
``` | ||||||
|
||||||
## Rationale | ||||||
|
||||||
The reason for having a relayer URI to pass data is due to limitations in the size of the data that can be transmitted wirelessly between devices directly. For example, QR codes have a maximum character size of 7,089 characters currently, but a user can attempt to buy an indefinite number of items in a single checkout transaction. By having a relayer URI, we can theoretically pass as much calldata as we desire to the customer’s wallet, as long as they fetch from the URI. | ||||||
|
||||||
[ERC-681](erc-681.md) URIs were also permitted to enable possible direct peer to peer payments. It’s more likely that they’ll be occurring between two end user wallets rather than between a customer and a merchant, but it would be good to include in the event the dapp only requires a simple send transaction to execute the checkout. | ||||||
|
||||||
## Security Considerations | ||||||
In the case of an [ERC-681](erc-681.md) URI, the same security considerations apply here. The wallet should display the amount and asset being transferred as well as the recipient very clearly to the customer, and users should only execute transactions using [ERC-681](erc-681.md) URIs from trusted dapps. | ||||||
|
||||||
With regards to the relayer URI, since it is a publicly facing URI, it’s possible that anyone can make a fetch to it, grab the data, and submit transactions of their own to execute a checkout on someone else’s behalf. To mitigate this, we made a verification code as an optional part of the standard. The verification code is only passed through via the RPC call and is expected to be passed onto the customer’s wallet via some sort of contactless communication mechanism. This way, the data is not accessible to a random person on the internet and can only be accessed from the intended customer’s wallet. | ||||||
|
||||||
|
||||||
## Copyright | ||||||
|
||||||
Copyright and related rights waived via [CC0](../LICENSE.md). |
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 abstract should contain enough detail to give the reader a high-level (but still technical) overview of how your proposal accomplishes its goals.