Skip to content

ERC-1066: FISSION Codes

Broadly applicable status codes for Ethereum smart contracts.

CircleCI Maintainability

This standard outlines a common set of Ethereum status codes (ESC) in the same vein as HTTP statuses. This provides a shared set of signals to allow smart contracts to react to situations autonomously, expose localized error messages to users, and so on.

The current state of the art is to either revert and require human intervention, or return a Boolean pass/fail status. Status codes are similar-but-orthogonal to reverting with a reason, but aimed at automation and translation.

As is the case with HTTP, having a standard set of known codes has many benefits for developers. They remove friction from needing to develop your own schemes for every contract, makes inter-contract automation easier, and makes it easier to broadly understand which of the finite states your request produced. Importantly, it makes it much easier to distinguish between expected errors states, and truly exceptional conditions that require halting execution.

Motivation

Autonomy

Smart contracts are largely intended to be autonomous. While each contract may define a specific interface, having a common set of semantic codes can help developers write code that can react appropriately to various situations.

Semantic Density

HTTP status codes are widely used for this purpose. BEAM languages use atoms and tagged tuples to signify much the same information. Both provide a lot of information both to the programmer (debugging for instance), and to the program that needs to decide what to do next.

ESCs convey a much richer set of information than Booleans, and are able to be reacted to autonomously unlike arbitrary strings.

User Feedback

Since status codes are finite and known in advance, we can provide global, human-readable sets of status messages. These may also be translated into any language, differing levels of technical detail, added as revert messages, natspecs, and so on.

We also see a desire for this in transactions, and there's no reason that ESCs couldn't be used by the EVM itself.

More than Pass/Fail

While clearly related, status codes are complementary to "revert with reason". ESCs are not limited to rolling back the transaction, and may represent known error states without halting execution. They may also represent off-chain conditions, supply a string to revert, signal time delays, and more.

Specification

Format

Codes are returned as the first value of potentially multiple return values.

// Status only

function isInt(uint num) public pure returns (byte status) {
    return hex"01";
}

// Status and value

uint8 private counter;

function safeIncrement(uint8 interval) public returns (byte status, uint8 newCounter) {
    uint8 updated = counter + interval;

    if (updated >= counter) {
        counter = updated;
        return (hex"01", updated);
    } else {
        return (hex"00", counter);
    }
}

In the rare case that there are multiple codes required to express an idea, they should be organized in ascending order.

Code Table

X. Low Nibble 0. Generic 10. Permission 20. Find/Match/&c 30. Negotiation / Offers 40. Availability 50. 60. 70. 80. 90. A0. B0. C0. D0. E0. Cryptography F0. Off Chain
0. Failure 0x00 Failure 0x10 Disallowed 0x20 Not Found 0x30 Other Party Disagreed 0x40 Unavailable or Expired 0xE0 Decrypt Failure 0xF0 Off Chain Failure
1. Success 0x01 Success 0x11 Allowed 0x21 Found 0x31 Other Party Agreed 0x41 Available 0xE1 Decrypt Success 0xF1 Off Chain Success
2. Accepted / Started 0x02 Accepted / Started 0x12 Requested Permission 0x22 Match Request Sent 0x32 Sent Offer 0xE2 Signed 0xF2 Off Chain Process Started
3. Awaiting Others 0x03 Awaiting 0x13 Awaiting Permission 0x23 Awaiting Match 0x33 Awaiting Their Ratification 0x43 Not Yet Available 0xE3 Other Party Signature Required 0xF3 Awaiting Off Chain Completion
4. Action Required / Awaiting You 0x04 Action Required 0x14 Awaiting Your Permission 0x34 Awaiting Your Ratification 0x44 Awaiting Your Availability* 0xE4 Your Signature Required 0xF4 Off Chain Action Required
5.
6.
7.
8.
9.
A.
B.
C.
D.
E.
F. Meta/Info 0x0F Metadata Only 0xFF Data Source is Off Chain (ie: no guarantees)
  • Unused regions are available for further extension or custom codes
  • You may need to scroll the tables horizontally (they're pretty wide)

Codes break nicely into a 16x16 matrix, represented as a 2-digit hex number. The high nibble represents the code's kind or "category", and the low nibble contains the state or "reason". We present them below as separate tables per range for explanatory and layout reasons.

Unspecified codes are not free for arbitrary use, but rather open for further specification.

Generic

General codes. These double as bare "reasons", since 0x01 == 1.

Code Description
0x00 Failure
0x01 Success
0x02 Accepted / Started
0x03 Awaiting / Before
0x04 Action Required
0x05 Expired
0x06
0x07
0x08
0x09
0x0A
0x0B
0x0C
0x0D
0x0E
0x0F Meta or Info Only

Permission

Related to permisson, authorization, approval, and so on.

Code Description
0x10 Disallowed
0x11 Allowed
0x12 Requested Permission
0x13 Awaiting Permission
0x14 Awaiting Your Permission
0x15 No Longer Allowed
0x16
0x17
0x18
0x19
0x1A
0x1B
0x1C
0x1D
0x1E
0x1F Permission Meta or Info

Find, Match, &c

This range is broadly intended for finding and matching. Data lookups and order matching are two common use cases.

Code Description
0x20 Not Found
0x21 Found
0x22 Match Request Sent
0x23 Awaiting Match
0x24 Match Request Received
0x25 Out of Range
0x26
0x27
0x28
0x29
0x2A
0x2B
0x2C
0x2D
0x2E
0x2F Matching Meta or Info

Negotiation, Terms, and Offers

Negotiation, and very broadly the flow of such transactions. Note that "other party" may be more than one actor (not necessarily the sender).

Code Description
0x30 Other Party Disagreed
0x31 Other Party Agreed
0x32 Sent Offer
0x33 Awaiting Their Ratification
0x34 Awaiting Your Ratification
0x35 Offer Expired
0x36
0x37
0x38
0x39
0x3A
0x3B
0x3C
0x3D
0x3E
0x3F Negotiation Meta or Info

Availability

Service or action availability.

Code Description
0x40 Unavailable
0x41 Available
0x42 You May Begin
0x43 Not Yet Available
0x44 Awaiting Your Availability
0x45 No Longer Available
0x46
0x47
0x48
0x49
0x4A
0x4B
0x4C
0x4D
0x4E
0x4F Availability Meta or Info

0x5_ TBD

Currently unspecified

0x6_ TBD

Currently unspecified

0x7_ TBD

Currently unspecified

0x8_ TBD

Currently unspecified

0x9_ TBD

Currently unspecified

Application-Specific Codes

Contracts may have special states that they need to signal. This proposal only outlines the broadest meanings, but implementers may have very specific meanings for each, as long as they are coherent with the broader definition.

Code Description
0xA0 App-Specific Failure
0xA1 App-Specific Success
0xA2 App-Specific Acceptance / Start
0xA3 App-Specific Awaiting / Before
0xA4 App-Specific Action Required
0xA5 App-Specific Expiry
0xA6
0xA7
0xA8
0xA9
0xAA
0xAB
0xAC
0xAD
0xAE
0xAF App-Specific Meta or Info

0xB_ TBD

Currently unspecified

0xC_ TBD

Currently unspecified

0xD_ TBD

Currently unspecified

Cryptography and Authentication

Actions around signatures, cryptography, signing, and application-level authentication.

The meta code 0xEF is often used to signal a payload descibing the algorithm or process used.

Code Description
0xE0 Decrypt Failure
0xE1 Decrypt Success
0xE2 Signed
0xE3 Their Signature Required
0xE4 Your Signature Required
0xE5 Auth Expired
0xE6
0xE7
0xE8
0xE9
0xEA
0xEB
0xEC
0xED
0xEE
0xEF Crypto Info or Meta

0xF0 Off-Chain

For off-chain actions. Much like th 0x0_: Generic range, 0xF_ is very general, and does little to modify the reason.

Among other things, the meta code 0xFF may be used to describe what the off-chain process is.

Code Description
0xF0 Off-Chain Failure
0xF1 Off-Chain Success
0xF2 Off-Chain Process Stared
0xF3 Awaiting Off-Chain Completion
0xF4 Off-Chain Action Required
0xF5 Off-Chain Service Unavailable
0xF6
0xF7
0xF8
0xF9
0xFA
0xFB
0xFC
0xFD
0xFE
0xFF Off-Chain Info or Meta

Example Function Change

uint256 private startTime;
mapping(address => uint) private counters;

// Before
function increase() public returns (bool _available) {
    if (now < startTime && counters[msg.sender] == 0) {
        return false;
    };

    counters[msg.sender] += 1;
    return true;
}

// After
function increase() public returns (byte _status) {
    if (now < start) { return hex"43"; } // Not yet available
    if (counters[msg.sender] == 0) { return hex"10"; } // Not authorized

    counters[msg.sender] += 1;
    return hex"01"; // Success
}

Example Sequence Diagrams

0x03 = Waiting
0x31 = Other Party (ie: not you) Agreed
0x41 = Available
0x43 = Not Yet Available


                          Exchange


AwesomeCoin                 DEX                     TraderBot
     +                       +                          +
     |                       |       buy(AwesomeCoin)   |
     |                       | <------------------------+
     |         buy()         |                          |
     | <---------------------+                          |
     |                       |                          |
     |     Status [0x43]     |                          |
     +---------------------> |       Status [0x43]      |
     |                       +------------------------> |
     |                       |                          |
     |                       |        isDoneYet()       |
     |                       | <------------------------+
     |                       |                          |
     |                       |       Status [0x43]      |
     |                       +------------------------> |
     |                       |                          |
     |                       |                          |
     |     Status [0x41]     |                          |
     +---------------------> |                          |
     |                       |                          |
     |       buy()           |                          |
     | <---------------------+                          |
     |                       |                          |
     |                       |                          |
     |     Status [0x31]     |                          |
     +---------------------> |      Status [0x31]       |
     |                       +------------------------> |
     |                       |                          |
     |                       |                          |
     |                       |                          |
     |                       |                          |
     +                       +                          +
0x01 = Generic Success
0x10 = Disallowed
0x11 = Allowed

                                              Token Validation


           Buyer                  RegulatedToken           TokenValidator               IDChecker          SpendLimiter
             +                          +                         +                         +                   +
             |        buy()             |                         |                         |                   |
             +------------------------> |          check()        |                         |                   |
             |                          +-----------------------> |          check()        |                   |
             |                          |                         +-----------------------> |                   |
             |                          |                         |                         |                   |
             |                          |                         |         Status [0x10]   |                   |
             |                          |       Status [0x10]     | <-----------------------+                   |
             |        revert()          | <-----------------------+                         |                   |
             | <------------------------+                         |                         |                   |
             |                          |                         |                         |                   |
+---------------------------+           |                         |                         |                   |
|                           |           |                         |                         |                   |
| Updates ID with provider  |           |                         |                         |                   |
|                           |           |                         |                         |                   |
+---------------------------+           |                         |                         |                   |
             |                          |                         |                         |                   |
             |         buy()            |                         |                         |                   |
             +------------------------> |        check()          |                         |                   |
             |                          +-----------------------> |         check()         |                   |
             |                          |                         +-----------------------> |                   |
             |                          |                         |                         |                   |
             |                          |                         |       Status [0x11]     |                   |
             |                          |                         | <-----------------------+                   |
             |                          |                         |                         |                   |
             |                          |                         |                         |   check()         |
             |                          |                         +-------------------------------------------> |
             |                          |                         |                         |                   |
             |                          |                         |                         |  Status [0x11]    |
             |                          |       Status [0x11]     | <-------------------------------------------+
             |        Status [0x01]     | <-----------------------+                         |                   |
             | <------------------------+                         |                         |                   |
             |                          |                         |                         |                   |
             |                          |                         |                         |                   |
             |                          |                         |                         |                   |
             +                          +                         +                         +                   +

Rationale

Encoding

ESCs are encoded as a byte. Hex values break nicely into high and low nibbles: category and reason. For instance, hex"01" stands for general success and hex"00" for general failure.

byte is quite lightweight, and can be easily packed with multiple codes into a bytes32 (or similar) if desired. It is also easily interoperable with uint8, cast from enums, and so on.

Alternatives

Alternate schemes include bytes32 and uint8. While these work reasonably well, they have drawbacks.

uint8 feels even more similar to HTTP status codes, and enums don't require as much casting. However does not break as evenly as a square table (256 doesn't look as nice in base 10).

Packing multiple codes into a single bytes32 is nice in theory, but poses additional challenges. Unused space may be interpeted as 0x00 Failure, you can only efficiently pack four codes at once, and there is a challenge in ensuring that code combinations are sensible. Forcing four codes into a packed representation encourages multiple status codes to be returned, which is often more information than strictly nessesary. This can lead to paradoxical results (ex 0x00 and 0x01 together), or greater resorces allocated to interpreting 2564 (4.3 billion) permutations.

Multiple Returns

While there may be cases where packing a byte array of ESCs may make sense, the simplest, most forwards-compatible method of transmission is as the first value of a multiple return.

Familiarity is also a motivating factor. A consistent position and encoding together follow the principle of least surprise. It is both viewable as a "header" in the HTTP analogy, or like the "tag" in BEAM tagged tupples.

Human Readable

Developers should not be required to memorize 256 codes. However, they break nicely into a table. Cognitive load is lowered by organizing the table into categories and reasons. 0x10 and 0x11 belong to the same category, and 0x04 shares a reason with 0x24

While this repository includes helper enums, we have found working directly in the hex values to be quite natural. ESC 0x10 is just as comfortable as HTTP 401, for example.

Extensiblilty

The 0xA category is reserved for application-specific statuses. In the case that 256 codes become insufficient, bytes1 may be embedded in larger byte arrays.

EVM Codes

The EVM also returns a status code in transactions; specifically 0x00 and 0x01. This proposal both matches the meanings of those two codes, and could later be used at the EVM level.

Empty Space

Much like how HTTP status codes have large unused ranges, there are totally empty sections in this proposal. The intent is to not impose a complete set of codes up front, and to allow users to suggest uses for these spaces as time progresses.

Nibble Order

Nibble order makes no difference to the machine, and is purely mnemonic. This design was originally in opposite order, but changed it for a few convenience factors. Since it's a different scheme from HTTP, it may feel strange initially, but becomes very natural after a couple hours of use.

Short Forms

Generic is 0x0_, general codes are consistent with their integer representations

hex"1" == hex"01" == 1 // with casting

Contract Categories

Many applications will always be part of the same category. For instance, validation will generally be in the 0x10 range.

contract Whitelist {
    mapping(address => bool) private whitelist;
    uint256 private deadline;
    byte constant private prefix = hex"10";

    check(address _, address _user) returns (byte _status) {
        if (now >= deadline)  { return prefix | 5; }
        if (whitelist[_user]) { return prefix | 1; }
        return prefix;
    }
}

Helpers

This above also means that working with app-specific enums is slightly easier:

enum Sleep {
    Awake,
    Asleep,
    REM,
    FallingAsleep
}

// From the helper library

function appCode(Sleep _state) returns (byte code) {
    return byte(160 + _state); // 160 = 0xA0
}

// Versus

function appCode(Sleep _state) returns (byte code) {
    return byte((16 * _state) + 10); // 10 = 0xA
}

Implementation

Reference cases and helper libraries (Solidity and JS) can be found at: