diff --git a/ERCS/erc-7798.md b/ERCS/erc-7798.md new file mode 100644 index 0000000000..ad36675698 --- /dev/null +++ b/ERCS/erc-7798.md @@ -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 +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. + +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`. + +- `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 + +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)** + +```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).