ERC-5453 Endorsement Standard

2 Likes

We’re developing something along this line! DM me if ur interested

1 Like

Great to hear. Are you still developing this implementation? @onjas

Hi @frangio, just wanna sincerely invite you to comment on EIP-5453 (Endorsement) given that you are driving #5782 as well as you are the main author of open-zeppelin. I think EIP-5453 can be a more general way to signal approval of a transaction. A working reference implementation is in [WIP] Create RefImpl for ERC-5453 Smart Endorsement by xinbenlv · Pull Request #1 · ercref/contracts · GitHub (Work-In-Progress)

How does this compare to EIP-712 signatures? As far as I can tell EIP-712 signatures by themselves already serve as a general way to signal approval for things. What does this EIP offer on top of that?

Hi @frangio,

Thank you for the question.

To give an immediate brief answer:

  • EIP-712 regulates how to hash and sign a general struct.
  • EIP-5453 regulates how to allow functions to take in a digital signature from arbitrary user to authenticate behaviors.
  • EIP-5453 is a way to indicate “an intent to permit”. When used with ERC20, it directly compete with EIP-2612. But EIP-5453 also applies to other functions not just ERC20 transfer. It supports all functions that have an ending bytes _data. Sitenote: This behavior already exist in many existing ERCs‘ function e.g. ERC721 and ERC1150. I am propose to recognize this behavior with EIP-5750).

Let me use a metaphor: If you happen to be familiar with the “bank check” concept:

  • 712 regulates what the signature look like (also we to get data)
  • 5453 regulates “assuming there is a check, let’s designate the top 20% of white area in the back of the check to be endorsement area, and put a signature there. By the way, there should be a date”

And here is why:

5453 focus on defining function behavior, so it can use 712 in some part of the payload, but not all. Also it solves a problem that 712 doesn’t solve: how to identify where the endorsement is, and what happen if there are nested endorsements when it’s a nested function call, e.g.

5453 is expected to be used with 712 in a lot of case. The implementer of 5453 usually will (can / might need) use 712’s spec for generating a msgDigest for any particular non-trivial function parameter. 712 didn’t determine how and where a function call will use the signature.

5453 also have a very strict and specific schema that is tailored towards being used in function extra data for endorsement(authorization). This is not as flexible as 712. For example, such specific schema includes consideration of nonce, valid_since and valid_by. In 712, such thing can be an implementation choice when implementers a choosing a struct. In 5453, with the goal of “endorsement” in mind, it asks for a very specific format to encode nonce, valid_since and valid_by to avoid replay-attack, and also so that endorsers have a clear expectation when will their endorsement be valid.

One may ask, then why just say “Put a 712 structure of ” in the ending of an extra-data function then you are good. Yes, that’s pretty much what we are doing here except for we might choose a simpler and rigid struct to reduce implementers’ chance of error, because the “endorsement” are usually used for authorization so the simpler the better. There are still some WIP details that author (me for, any co-author welcome too) needs to consider and design. Your feedback&advice is greatly appreciated. We will modify “Spec” and “Rationale” sections accordingly if changed.

Let me know if this help explain your question. It might still be a bit unclear,
I am currently writing a few coding reference implementation examples to demonstrate what I mean. Likely to publish in ERCRef repo.

Relationship with other EIPs

Also maybe worth mention,

  • we expect 5453 implementations to be used with 1271 too, just in case one might wonder.
  • we expect 5453 to be able to replace EIP-2612: Permit Extension for EIP-20: Signed Approval but 5453 can be used as Permit Extension in more general way: it supports all other functions, not just ERC20 transfer

Some early RefImp Example (pseudo code)

Example 0: Permit for ERC721

contract Foo20 is ERC721 {
   const uint256 EDMT_LEN = ...; //  
   function transferFrom(address from, address to, uint256 tokenId, bytes calldata _data) {
      address endorserMaybe = _isEndorsedBy(_data); // for simplicity assume entire data is endorsment
      require(from == msg.sender || from == endorser); // ignore Approval for simplicity
      _owner[tokenId] = to;
      emit...
   }
   function _isEndorsedBy(bytes _endorsement) returns (address) {
      if (!endorsements[:8] ==ASCII"ENDORSED") return address(0);
      else {
         byte eType = endorsement[endorsement.length - 8];
      }
   } // It can be more graceful represented as modifier if solidity supports lambda
}

Example 1: Nested endorsement used in multi-hop function call

contract FooNFT {
  function swap(address tokenHolder, uint256 tokenId, bytes calldata data) {
    require(isEndorsedBy(data, tokenHolder));
    require(ownerOf(tokenId, tokenHolder));
    _burn(tokenId);
    destContract.mint(tokenId, tokenHolder, data[subsetlenth:]); // pseudo code, just to demonstrate ways to call the mint.
  }
} 

contract BarNFT {
... // dest contract
  function mint(address to, uint256 tokenId, bytes calldata data) { 
    require(isEndorsedBy(data, minterAdmin));
    _mint(to, tokenId, data[remainlength:]);
  }
  function _mint(... bytes calldata reason) {
    .. using the rest data as "reason"...
  }
}

In this way, user Alice could get the BarNFT’s minterAdmin’s endorsement to mint a token.
user Bob could help user Charlie to call the swap function with Charlie’s endorsement if the same minterAdmin also permit with an endorsement.

Example 2: Two endorsements in one call

Here is another example MergeNFT using endorsements from two people at the same call, two token in, merge and create a third NFT

function mergeTwoNFTs(uint256 tokenIn1, uint256 tokenIn2, bytes calldata data) returns (uint256 tokenOut) {
  parse and verify endorsement 1 from data[datalength - 1*endorselength:]
  parse and verify endorsement 2 from data[datalength - 2*endorselength:datalength - 1*endorselength];
  verify endorser1 owns tokenIn1;
  verify endorser2 owns tokenIn2;
  _burn(tokenIn1);
  _burn(tokenIn2);
  _mint(tokenOut);
  return tokenOut;
}

@frangio I updated the EIP-5453 and a reference implementation is shared in ercref-contracts/ERCs/eip-5453 at main · ercref/ercref-contracts · GitHub
Your feedback is greatly appreciated.

Most recent version ercref-contracts/AERC5453.sol at main · ercref/ercref-contracts · GitHub and a simple usage example

@frangio for comment~

Cross posting a comment from ERC 4337: Account Abstraction via Entry Point Contract specification - #58 by yoavw