Skip to content
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

Rich Revert Reasons #32

Closed
dorothy-zbornak opened this issue Apr 19, 2019 · 1 comment
Closed

Rich Revert Reasons #32

dorothy-zbornak opened this issue Apr 19, 2019 · 1 comment
Labels
status: implemented Proposed changes have been implemented (and deployed, if smart contract) type: core

Comments

@dorothy-zbornak
Copy link

dorothy-zbornak commented Apr 19, 2019

Summary

Instead of throwing opaque string reverts, 3.0 contracts will instead throw custom, ABI-encoded "rich" revert types augmented with much more useful parameters.

Motivation

Reverting with expressive error data will enable developers to create more robust applications built on top of the 0x protocol.

Additionally, this is a critical step towards our goal of becoming a language-agnostic protocol, wherein applications can rely more on the contracts themselves and less on off-chain tooling to validate and debug interactions.

Specification

Encoding

Standard string reverts (à la Soldity's require() and revert() builtins) are ABI-encoded as a function call with signature Error(string).

For example, a revert("foobar") would encode as:

# 4-byte function selector (keccak of "Error(string)")
08c379a0
# Offset to the error string calldata.
0000000000000000000000000000000000000000000000000000000000000020
# -> Error string data
    # Length of string (6)
    0000000000000000000000000000000000000000000000000000000000000006
    # String bytes
    0000000000000000000000000000000000000000000000000000666f6f626172

Our rich reverts follow the same encoding rules but with varying function signatures.

For example, the rich revert SignatureError has the signature:

SignatureError(uint8 errorCode, bytes32 hash, address signer, bytes signature)

If we construct it with the following values:

SignatureError(
    // errorCode
    3,
    // signature hash
    0xa3dcd8f6179b531a8c33b675b700708090d4e94d6f6f4cd9e652239a6225db45,
    // signer
    0x828f817d6612f7b477d66591ff96a9e064bcc98a,
    // signature
    0x010aeaf352d05c6dcf64882760014703432133689f4507cd91e81aaa3b289223
      507bc8cf2629ff3ea8a468013a49b32227900be174575ce135ed2560c236dba6
      8802
)

The resulting encoding will be:

# 4-byte function selector (keccak of "SignatureError(uint8,bytes32,address,bytes)")
7e5a2318
# errorCode, padded to 32-bytes
0000000000000000000000000000000000000000000000000000000000000003
# Signature hash
a3dcd8f6179b531a8c33b675b700708090d4e94d6f6f4cd9e652239a6225db45
# Offset to signature bytes data
0000000000000000000000000000000000000000000000000000000000000060
# -> Signature bytes data
    # Length of bytes (66)
    0000000000000000000000000000000000000000000000000000000000000042
    # bytes data
    010aeaf352d05c6dcf64882760014703432133689f4507cd91e81aaa3b289223
    507bc8cf2629ff3ea8a468013a49b32227900be174575ce135ed2560c236dba6
    8802

Decoding

Nodes will only return revert data for eth_call operations, though it is possible (but not foolproof) to replay a failed transaction using eth_call and a block number.

Furthermore, with geth there is an issue where the JSON-RPC response for a successful eth_call is indistinguishable from a revert. For this reason, (at minimum) we need to check the leading 4 bytes of the return data against a mapping of known error selectors to detect that a revert actually occurred. This is a little inelegant, but with roughly 4 billion combinations of leading 4 bytes, combined with more rigorous conformance checks, false positives should be extremely rare.

Once the exact error type is detected, ABI decoding tools can be used to extract individual parameter values.

For environments where ABI decoding tools are not exposed/available, we will also be deploying a helper contract that decomposes encoded error bytes into its constituent fields.

Proposed Error Types

Thus far, we propose the following rich revert types:

  • General
    • Error(string message)
      • Selector: 0x08c379a0
      • The standard string revert type.
  • Signature Validation
    • SignatureError(uint8 errorCode, bytes32 hash, address signer, bytes signature)
      • Selector: 0x7e5a2318
      • Sundry validation failures:
        • BadSignature
        • InvalidLength
        • Unsupported
        • Illegal
        • InappropriateSignatureType
    • SignatureValidatorError(bytes32 hash, address signer, bytes signature, bytes errorData)
      • Selector: 0x169fad8c
      • Validator contract failure with SignatureType.Validator.
    • SignatureWalletError(bytes32 hash, address wallet, bytes signature, bytes errorData)
      • Selector: 0x1b8388f7
      • Wallet contract failure with SignatureType.Wallet.
    • SignatureOrderValidatorError(bytes32 hash, address signer, bytes signature, bytes errorData)
      • Selector: 0xfabf4577
      • Order Validator contract with SignatureType.OrderValidator.
    • SignatureWalletOrderValidatorError(bytes32 hash, address wallet, bytes signature, bytes errorData)
      • Selector: 0xa85f3360
      • Order Wallet contract failure with SignatureType.WalletOrderValidator.
  • Order State
    • OrderStatusError(uint8 currentStatus, bytes32 orderHash)
      • Selector: 0x2992a71c
      • Invalid order status for operation.
    • OrderEpochError(address maker, address sender, uint256 currentEpoch)
      • Selector: 0x4ad31275
      • Invalid order epoch (salt) for operation.
    • InvalidSenderError(bytes32 orderHash, address sender)
      • Selector: 0x95b59997
      • Invalid sender for operation.
    • InvalidTakerError(bytes32 orderHash, address taker)
      • Selector: 0xfdb328be
      • Invalid taker for operation.
    • InvalidMakerError(bytes32 orderHash, address maker)
      • Selector: 0x26bf55d9
      • Invalid maker for operation.
  • Fills
    • FillError(uint8 errorCode, bytes32 orderHash)
      • Selector: 0xe94a7ed0
      • Sundry fill failures:
        • InvalidTakerAmount
        • TakerOverpay
        • Overfill
        • InvalidFillPrice
    • AssetProxyDispatchError(uint8 errorCode, bytes32 orderHash, bytes assetData)
      • Selector: 0x488219a6
      • Unable to dispatch order to asset proxy:
        • InvalidAssetDataLength
        • UnknownAssetProxy
    • AssetProxyTransferError(bytes32 orderHash, bytes assetData, bytes errorData)
      • Selector: 0x4678472b
      • Failure during asset proxy execution (e.g., ERC20 transfer() reverting)
    • NegativeSpreadError(bytes32 leftOrderHash, bytes32 rightOrderHash)
      • Selector: 0xb6555d6f
      • Negative spread during matchOrders()
    • IncompleteFillError(bytes32 orderHash)
      • Selector: 0x152aa60e
      • Negative spread during matchOrders()
  • Transactions
    • TransactionError(uint8 errorCode, bytes32 transactionHash)
      • Selector: 0xf5985184
      • Sundry transaction failures:
        • NoReentrancy
        • AlreadyExecuted
    • TransactionSignatureError(bytes32 transactionHash, address signer, bytes signature)
      • Selector: 0xbfd56ef6
      • Invalid transaction signature.
    • TransactionExecutionError(bytes32 transactionHash, bytes errorData)
      • Selector: 0x20d11f61
      • Couldn't full fill order with fillOrKill().
  • Administrative
    • AssetProxyExistsError(address proxy)
      • Selector: 0xcc8b3b53
      • Attempting to register existing asset proxy.
@mintcloud
Copy link
Contributor

Implemented in #56

@mintcloud mintcloud added status: implemented Proposed changes have been implemented (and deployed, if smart contract) type: core and removed 3.0 labels Apr 10, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: implemented Proposed changes have been implemented (and deployed, if smart contract) type: core
Projects
None yet
Development

No branches or pull requests

3 participants