Closed yaronvel closed 2 years ago
Your assumption about DAOs is a bit problematic, because they are not actually able to read events emitted in contracts. Only external listeners do that. ( Please correct me if this has been changed recently ).
While DAO's should already have an internal state that is updated upon successful payment execution.
I do see value in standardising the payment interface and being able to roll out a generic event listener.
I would love to see some use cases that you're thinking of.
@mickys they idea is that external listener will do it in behalf of the DAO. Note that this event does not guarantee the delivery of the product. On gives a proof for the payment. So in case of a dispute, an human agent will have to act on behalf of the DAO.
Adding @leviadam from dao stack to the discussion to give more insights on DAO needs.
@mickys regarding internal DAO state. It is a proof for the dao members at best. One cannot expect merchant customer support to read the DAO code and understand the proof.
I think it is a good idea that transfers will have an identifier. It is important for example for UIs of DAOs referencing transfers.
I might advise to also standard the way data is constructed. Like a hash of a counter+contract address. This cannot be enforced, but can still be useful.
Interesting idea. One brainstorm input: how will a return
/ cancel of payment
look like in this ERC?
@leviadam contract address is already embedded in the event topic. As for standardizing the rest, would be happy to hear suggestions. If we had ideas on what should be there we could add specific fields.
@xinbenlv interesting question. It give rise to a lot of questions like whether returning the payment in delay should be allowed and what is the actual value of delayed payment.
On a practical level though, at least on first stage, the needed software stack is on the merchant side. We cannot expect the consumer to run its on client for that.
Interesting idea.
I agree with @xinbenlv - I think that in order to have a complete solution that allows 3rd parties to track payments, the solution should also include cancellations/refunds etc., especially if 3rd parties are creating their own flows based on these proofs.
Great proposal @yaronvel !
@mickys has a good point since the external listener introduces a point of centralization and increases friction. I assume to consume that information some kind of relay should be involved to update the DAO of the payment execution.
In the attempt to standardize the payment interface it could be useful to include a callback function besides the emission of an event.
Something like:
function paymentCallback(address indexed _payer, address _token, uint _amount, bytes _data)
In the context of the PizzaStore, it could look like this.
function buyPizzaWithEther(uint _slices, address _beneficiary, string _homeAddress) public payable {
require(msg.value == _slices * SLICE_PRICE_IN_ETH);
bytes32 data = keccak256(abi.encodePacked(_slices,_homeAddress));
emit ProofOfPayment(_beneficiary,0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE,msg.value,data);
if (isContract(_beneficiary)) {
ContractReceiver rx = ContractReceiver( _beneficiary );
require(
address(rx).call.value(0)(
bytes4(keccak256("paymentCallback")),
0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE,
msg.value,
data
)
);
}
}
@yudilevi maybe this can be solved in application level.
There is no really payment cancellation, but rather transferring back ETH (or token).
The vendor can use same event to record the payment refund to the user and the _data
will contain relevant tag that denotes the cancellation.
I guess we can add as a convention that last byte in the data denotes whether it is payment or refund.
But it can also be reasoned by the _payer
and _payee
addresses.
@Alexintosh what you suggest will not be compatible with most existing deployed contracts. And the payment will just revert. For example if the payment is done from a gnosis multisig.
Your idea does make sense, but I am not sure why standards for all DAOs is needed here rather than dao-specific implementation.
Note that this standard is proposed only for the purpose of making it easier to build standard off-chain
tools to track payments.
For on-chain tracking, I am not sure standardization is needed.
Every dapp can implement the recording logic along with the execution logic (if needed).
@yaronvel I prefer an explicit argument over trying to figure it out by the _payer
/_payee
arguments. I think it will also keep it more generic.
For example, if 2 different entities have payments for each other, we would like to know whether a payment is a refund or not etc.
There might also be other different types of transfers that we might want to support later on.
@yudilevi can you propose argument type? should it be boolean? uint?
@yaronvel uint8 _type
? uint8 should suffice I think.
@yudilevi ok, I see. Sure, we are fine with adding it, but can you please offer a spec for the different values? 0 is payment. 1 is refund? other values are also defined? Please advise.
@yaronvel what do you think about defining it as bytes32, declaring some pre-defined values like "payment" and "refund" and allowing custom values? I can see values like "fee" or "subscription" in the future but I wouldn't want to limit apps to these as they might be a bit too narrow for some.
The handler can decide ignore the values and payment providers can declare application specific values? Do you think that it gives too much flexibility (and possibly lead to non standard implementations)?
@yudilevi can live with it, though maybe uint256
is better, because comparison is easier. unless you aim to hold sha3
of a string?
I am fine with both. Just does not like bytes32
much because how solidity treats it.
I mean it will force you to do:
bytes32 constant REFUND = bytes32(0)
.
Also at the backend level it give rise to confusing endianess. Meaning the order of bytes.
@yaronvel I agree, it might be too much of a hassle. So uint256 with some predefined values, reserved range and application specific custom values? :)
@yudilevi sure, want to take the lead on the predefined value and ranges spec? can add you to the EIP. PR is welcomed (though not sure if possible), or just write something here.
There has been no activity on this issue for two months. It will be closed in a week if no further activity occurs. If you would like to move this EIP forward, please respond to any outstanding feedback or add a comment indicating that you have addressed all required feedback and are ready for a review.
This is ready for review
There has been no activity on this issue for two months. It will be closed in a week if no further activity occurs. If you would like to move this EIP forward, please respond to any outstanding feedback or add a comment indicating that you have addressed all required feedback and are ready for a review.
Closing this issue for housekeeping purposes. People are welcome to continue discussing in this thread, but for additional visibility an EIP should be created or the conversation should be migrated to https://ethereum-magicians.org/
eip: ERC 1257 title: Proof of Payment (POP) Standard author: Victor Tran, and Yaron Velner (and future others) status: Draft type: ERC category ERC created: 2018-07-25
Proof of Payment
Simple Summary
Proof of Payment (POP) is an event (evm log) that provide a record of successful payment. Either via Ether or ERC20 token.
Abstract
Currently merchants and vendors in online stores are using transaction hash (tx hash) as a method to track user payment and provide a form of payment receipt. This approach stemmed from bitcoin payment methods, where the main form of payment is done by a human agent with a dedicated user interface. However, this approach cannot scale to payments that are done directly by smart contracts. E.g., multisig wallets, decentralized autonomous organizations (DAO), and exchange services. The root source is the difficulty to trace and parse payments done by so called "internal transactions". In this ERC, we propose a standard and generic way to provide a proof of payment with an evm log.
Motivation
Online merchants and vendors who provide physical goods in return to crypto payments have to be able to monitor payments done by their users, and users should also be able to provide a proof to the merchants about their payments (in the case of a dispute). Classical approaches are using the tx hash as a witness to a performed payment. In this approach the merchant's website generates a payment tx, and record the connection between the payment and the good to be delivered in an internal database.
The current approach, while being simple and elegant, will fail to scale to the case where the payment is done by a smart contract. A payment that is done by a smart contract is hard to detect and parse. A notable example is the coinbase deposit bug which allowed users to give themselves unlimited ether deposit balance. On the other hand, logging the payment as solidity event is easy to monitor with standard web3 tools.
The motivation to support payment by smart contracts is two-fold, namely, payment by online conversion services, and payment by autonomous organizations.
Online conversion services
Decentralized applications such as Kyber Network, Bancor, AirSwap, 0x and Etherdelta, make it possible for a merchant to accept payment in any ERC20 token and convert it to a currency of his choice (e.g, Ether). An important feature of such conversion service is that the conversion is done in the same transaction of the payment. Hence, the final payment should eventually be performed by a smart contract that does the conversion and send the output to the merchant's contract.
Decentralized autonomous organizations
The rise of DAO applications, such as DAOStack, Aragon, Gnosis, Harbour and Colony, makes it imperative to allow non-human agent to pay on behalf of the organization. In the most simple setting, payment by a multisig wallet is already hard to capture under the classical tx hash monitoring scheme. In the more advance setting, an autonomous organization might want to buy physical goods in an online stores for his members, but only provided a formal decision of the organization.
Specification
We introduce a standard to log payments that are done by smart contracts:
where:
_payer
denotes the agent who is paying for the product. We note that it need not bemsg.sender
._payee
denotes the agent who is receiving the payment._token
denotes the address of the token (e.g., ERC20, but could also be of other types) that is used for the payment. As a convention, we propose to denote Ether with0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
._amount
denotes the amount paid, in basic token units (e.g., wei)._data
denotes application specific auxiliary data. Usually in the form of the hash of multiple application specific parameters.Rationale
Making a community standard will help providing standard software libraries to allow crypto payments for merchants.
In this document, we assume the agent is paying to a contract it is familiar with, and typical token payment will be with the
approve
andtransferFrom
scheme. Under this assumption the proof of payment is guaranteed to be logged on the blockchain. We note that such proof does not guarantee the delivery of the product in any way. However, in the case of a dispute it could be used by both parties to make their claims, either in a court of law, or in a call with customer support center.We decided to explicitly log the beneficiary address in order to allow conversion services to pay on behalf of the original tx sender. The
_data
field is intended to encode a compact 32 bytes proof for application specific parameters that are relevant in the payment process.Implementation
As a tribute to the famous pizza purchase, we provide a sample implementation of a pizza store contract. The contract implement a proof of payment for payment either in Ether or Pizza token. In both cases the
_data
field is a witness to the number of ordered pizza slices and the beneficiary home address.UPDATE: a first mainnet implementation can be found here
Copyright
Copyright and related rights waived via CC0.