DCIPs/EIPS/eip-1066.md

599 lines
39 KiB
Markdown
Raw Normal View History

---
eip: 1066
title: Status Codes
author: Brooklyn Zelenka (@expede), Tom Carchrae (@carchrae), Gleb Naumenko (@naumenkogs)
discussions-to: https://ethereum-magicians.org/t/erc-1066-ethereum-status-codes-esc/
status: Stagnant
type: Standards Track
category: ERC
created: 2018-05-05
---
## Simple Summary
Broadly applicable status codes for smart contracts.
## Abstract
This standard outlines a common set of status codes in a similar vein to 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` on anything other than a clear success (ie: require human intervention), or return a low-context `true` or `false`. Status codes are similar-but-orthogonal to `revert`ing with a reason, but aimed at automation, debugging, and end-user feedback (including translation). _They are fully compatible with both `revert` and `revert`-with-reason._
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, truly exceptional conditions that require halting execution, normal state transitions, and various success cases.
## Motivation
### 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.
Status codes convey a much richer set of information [than Booleans](https://existentialtype.wordpress.com/2011/03/15/boolean-blindness/), and are able to be reacted to autonomously unlike arbitrary strings.
### User Experience (UX)
_End users get little to no feedback, and there is no translation layer._
Since ERC1066 status codes are finite and known in advance, we can leverage [ERC-1444](./eip-1444.md) to 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.
Status codes convey a much richer set of information than Booleans, and are able to be reacted to autonomously unlike arbitrary strings.
### Developer Experience (DX)
_Developers currently have very little context exposed by their smart contracts._
At time of writing, other than stepping through EVM execution and inspecting memory dumps directly, it is very difficult to understand what is happening during smart contract execution. By returning more context, developers can write well-decomposed tests and assert certain codes are returned as an expression of where the smart contract got to. This includes status codes as bare values, `event`s, and `revert`s.
Having a fixed set of codes also makes it possible to write common helper functions to react in common ways to certain signals. This can live off- or on-chain library, lowering the overhead in building smart contracts, and helping raise code quality with trusted shared components.
We also see a desire for this [in transactions](./eip-658.md), and there's no reason that these status codes couldn't be used by the EVM itself.
### Smart Contract Autonomy
_Smart contracts dont know much about the result of a request beyond pass/fail; they can be smarter with more context._
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.
While clearly related, status codes are complementary to `revert`-with-reason. Status codes 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.
All of this enables contracts to share a common vocabulary of state transitions, results, and internal changes, without having to deeply understand custom status enums or the internal business logic of collaborator contracts.
## Specification
### Format
Codes are returned either on their own, or as the first value of a multiple return.
```solidity
// 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);
}
}
```
### Code Table
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.
**NB: Unspecified codes are _not_ free for arbitrary use, but rather open for further specification.**
#### `0x0*` Generic
General codes. These double as bare "reasons", since `0x01 == 1`.
| Code | Description |
|--------|-----------------------------------------|
| `0x00` | Failure |
| `0x01` | Success |
| `0x02` | Awaiting Others |
| `0x03` | Accepted |
| `0x04` | Lower Limit or Insufficient |
| `0x05` | Receiver Action Requested |
| `0x06` | Upper Limit |
| `0x07` | [reserved] |
| `0x08` | Duplicate, Unnecessary, or Inapplicable |
| `0x09` | [reserved] |
| `0x0A` | [reserved] |
| `0x0B` | [reserved] |
| `0x0C` | [reserved] |
| `0x0D` | [reserved] |
| `0x0E` | [reserved] |
| `0x0F` | Informational or Metadata |
#### `0x1*` Permission & Control
Also used for common state machine actions (ex. "stoplight" actions).
| Code | Description |
|--------|---------------------------------------------------|
| `0x10` | Disallowed or Stop |
| `0x11` | Allowed or Go |
| `0x12` | Awaiting Other's Permission |
| `0x13` | Permission Requested |
| `0x14` | Too Open / Insecure |
| `0x15` | Needs Your Permission or Request for Continuation |
| `0x16` | Revoked or Banned |
| `0x17` | [reserved] |
| `0x18` | Not Applicable to Current State |
| `0x19` | [reserved] |
| `0x1A` | [reserved] |
| `0x1B` | [reserved] |
| `0x1C` | [reserved] |
| `0x1D` | [reserved] |
| `0x1E` | [reserved] |
| `0x1F` | Permission Details or Control Conditions |
#### `0x2*` Find, Inequalities & Range
This range is broadly intended for finding and matching. Data lookups and order matching are two common use cases.
| Code | Description |
|--------|-------------------------------------|
| `0x20` | Not Found, Unequal, or Out of Range |
| `0x21` | Found, Equal or In Range |
| `0x22` | Awaiting Match |
| `0x23` | Match Request Sent |
| `0x24` | Below Range or Underflow |
| `0x25` | Request for Match |
| `0x26` | Above Range or Overflow |
| `0x27` | [reserved] |
| `0x28` | Duplicate, Conflict, or Collision |
| `0x29` | [reserved] |
| `0x2A` | [reserved] |
| `0x2B` | [reserved] |
| `0x2C` | [reserved] |
| `0x2D` | [reserved] |
| `0x2E` | [reserved] |
| `0x2F` | Matching Meta or Info |
#### `0x3*` Negotiation & Governance
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` | Sender Disagrees or Nay |
| `0x31` | Sender Agrees or Yea |
| `0x32` | Awaiting Ratification |
| `0x33` | Offer Sent or Voted |
| `0x34` | Quorum Not Reached |
| `0x35` | Receiver's Ratification Requested |
| `0x36` | Offer or Vote Limit Reached |
| `0x37` | [reserved] |
| `0x38` | Already Voted |
| `0x39` | [reserved] |
| `0x3A` | [reserved] |
| `0x3B` | [reserved] |
| `0x3C` | [reserved] |
| `0x3D` | [reserved] |
| `0x3E` | [reserved] |
| `0x3F` | Negotiation Rules or Participation Info |
#### `0x4*` Availability & Time
Service or action availability.
| Code | Description |
|--------|------------------------------------------------------|
| `0x40` | Unavailable |
| `0x41` | Available |
| `0x42` | Paused |
| `0x43` | Queued |
| `0x44` | Not Available Yet |
| `0x45` | Awaiting Your Availability |
| `0x46` | Expired |
| `0x47` | [reserved] |
| `0x48` | Already Done |
| `0x49` | [reserved] |
| `0x4A` | [reserved] |
| `0x4B` | [reserved] |
| `0x4C` | [reserved] |
| `0x4D` | [reserved] |
| `0x4E` | [reserved] |
| `0x4F` | Availability Rules or Info (ex. time since or until) |
#### `0x5*` Tokens, Funds & Finance
Special token and financial concepts. Many related concepts are included in other ranges.
| Code | Description |
|--------|---------------------------------|
| `0x50` | Transfer Failed |
| `0x51` | Transfer Successful |
| `0x52` | Awaiting Payment From Others |
| `0x53` | Hold or Escrow |
| `0x54` | Insufficient Funds |
| `0x55` | Funds Requested |
| `0x56` | Transfer Volume Exceeded |
| `0x57` | [reserved] |
| `0x58` | Funds Not Required |
| `0x59` | [reserved] |
| `0x5A` | [reserved] |
| `0x5B` | [reserved] |
| `0x5C` | [reserved] |
| `0x5D` | [reserved] |
| `0x5E` | [reserved] |
| `0x5F` | Token or Financial Information |
#### `0x6*` TBD
Currently unspecified. (Full range reserved)
#### `0x7*` TBD
Currently unspecifie. (Full range reserved)
#### `0x8*` TBD
Currently unspecified. (Full range reserved)
#### `0x9*` TBD
Currently unspecified. (Full range reserved)
#### `0xA*` 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 Awaiting Others |
| `0xA3` | App-Specific Acceptance |
| `0xA4` | App-Specific Below Condition |
| `0xA5` | App-Specific Receiver Action Requested |
| `0xA6` | App-Specific Expiry or Limit |
| `0xA7` | [reserved] |
| `0xA8` | App-Specific Inapplicable Condition |
| `0xA9` | [reserved] |
| `0xAA` | [reserved] |
| `0xAB` | [reserved] |
| `0xAC` | [reserved] |
| `0xAD` | [reserved] |
| `0xAE` | [reserved] |
| `0xAF` | App-Specific Meta or Info |
#### `0xB*` TBD
Currently unspecified. (Full range reserved)
#### `0xC*` TBD
Currently unspecified. (Full range reserved)
#### `0xD*` TBD
Currently unspecified. (Full range reserved)
#### `0xE*` Encryption, Identity & Proofs
Actions around signatures, cryptography, signing, and application-level authentication.
The meta code `0xEF` is often used to signal a payload describing the algorithm or process used.
| Code | Description |
|--------|-------------------------------------|
| `0xE0` | Decrypt Failure |
| `0xE1` | Decrypt Success |
| `0xE2` | Awaiting Other Signatures or Keys |
| `0xE3` | Signed |
| `0xE4` | Unsigned or Untrusted |
| `0xE5` | Signature Required |
| `0xE6` | Known to be Compromised |
| `0xE7` | [reserved] |
| `0xE8` | Already Signed or Not Encrypted |
| `0xE9` | [reserved] |
| `0xEA` | [reserved] |
| `0xEB` | [reserved] |
| `0xEC` | [reserved] |
| `0xED` | [reserved] |
| `0xEE` | [reserved] |
| `0xEF` | Cryptography, ID, or Proof Metadata |
#### `0xF*` 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` | Awaiting Off-Chain Process |
| `0xF3` | Off-Chain Process Started |
| `0xF4` | Off-Chain Service Unreachable |
| `0xF5` | Off-Chain Action Required |
| `0xF6` | Off-Chain Expiry or Limit Reached |
| `0xF7` | [reserved] |
| `0xF8` | Duplicate Off-Chain Request |
| `0xF9` | [reserved] |
| `0xFA` | [reserved] |
| `0xFB` | [reserved] |
| `0xFC` | [reserved] |
| `0xFD` | [reserved] |
| `0xFE` | [reserved] |
| `0xFF` | Off-Chain Info or Meta |
### As a Grid
| | `0x0*` General | `0x1*` Permission & Control | `0x2*` Find, Inequalities & Range | `0x3*` Negotiation & Governance | `0x4*` Availability & Time | `0x5*` Tokens, Funds & Finance | `0x6*` TBD | `0x7*` TBD | `0x8*` TBD | `0x9*` TBD | `0xA*` Application-Specific Codes | `0xB*` TBD | `0xC*` TBD | `0xD*` TBD | `0xE*` Encryption, Identity & Proofs | `0xF*` Off-Chain |
|--------|------------------------------------------------|----------------------------------------------------------|--------------------------------------------|------------------------------------------------|-------------------------------------------------------------|----------------------------------------|-------------------|-------------------|-------------------|-------------------|-----------------------------------------------|-------------------|-------------------|-------------------|--------------------------------------------|------------------------------------------|
| `0x*0` | `0x00` Failure | `0x10` Disallowed or Stop | `0x20` Not Found, Unequal, or Out of Range | `0x30` Sender Disagrees or Nay | `0x40` Unavailable | `0x50` Transfer Failed | `0x60` [reserved] | `0x70` [reserved] | `0x80` [reserved] | `0x90` [reserved] | `0xA0` App-Specific Failure | `0xB0` [reserved] | `0xC0` [reserved] | `0xD0` [reserved] | `0xE0` Decrypt Failure | `0xF0` Off-Chain Failure |
| `0x*1` | `0x01` Success | `0x11` Allowed or Go | `0x21` Found, Equal or In Range | `0x31` Sender Agrees or Yea | `0x41` Available | `0x51` Transfer Successful | `0x61` [reserved] | `0x71` [reserved] | `0x81` [reserved] | `0x91` [reserved] | `0xA1` App-Specific Success | `0xB1` [reserved] | `0xC1` [reserved] | `0xD1` [reserved] | `0xE1` Decrypt Success | `0xF1` Off-Chain Success |
| `0x*2` | `0x02` Awaiting Others | `0x12` Awaiting Other's Permission | `0x22` Awaiting Match | `0x32` Awaiting Ratification | `0x42` Paused | `0x52` Awaiting Payment From Others | `0x62` [reserved] | `0x72` [reserved] | `0x82` [reserved] | `0x92` [reserved] | `0xA2` App-Specific Awaiting Others | `0xB2` [reserved] | `0xC2` [reserved] | `0xD2` [reserved] | `0xE2` Awaiting Other Signatures or Keys | `0xF2` Awaiting Off-Chain Process |
| `0x*3` | `0x03` Accepted | `0x13` Permission Requested | `0x23` Match Request Sent | `0x33` Offer Sent or Voted | `0x43` Queued | `0x53` Hold or Escrow | `0x63` [reserved] | `0x73` [reserved] | `0x83` [reserved] | `0x93` [reserved] | `0xA3` App-Specific Acceptance | `0xB3` [reserved] | `0xC3` [reserved] | `0xD3` [reserved] | `0xE3` Signed | `0xF3` Off-Chain Process Started |
| `0x*4` | `0x04` Lower Limit or Insufficient | `0x14` Too Open / Insecure | `0x24` Below Range or Underflow | `0x34` Quorum Not Reached | `0x44` Not Available Yet | `0x54` Insufficient Funds | `0x64` [reserved] | `0x74` [reserved] | `0x84` [reserved] | `0x94` [reserved] | `0xA4` App-Specific Below Condition | `0xB4` [reserved] | `0xC4` [reserved] | `0xD4` [reserved] | `0xE4` Unsigned or Untrusted | `0xF4` Off-Chain Service Unreachable |
| `0x*5` | `0x05` Receiver Action Required | `0x15` Needs Your Permission or Request for Continuation | `0x25` Request for Match | `0x35` Receiver's Ratification Requested | `0x45` Awaiting Your Availability | `0x55` Funds Requested | `0x65` [reserved] | `0x75` [reserved] | `0x85` [reserved] | `0x95` [reserved] | `0xA5` App-Specific Receiver Action Requested | `0xB5` [reserved] | `0xC5` [reserved] | `0xD5` [reserved] | `0xE5` Signature Required | `0xF5` Off-Chain Action Required |
| `0x*6` | `0x06` Upper Limit | `0x16` Revoked or Banned | `0x26` Above Range or Overflow | `0x36` Offer or Vote Limit Reached | `0x46` Expired | `0x56` Transfer Volume Exceeded | `0x66` [reserved] | `0x76` [reserved] | `0x86` [reserved] | `0x96` [reserved] | `0xA6` App-Specific Expiry or Limit | `0xB6` [reserved] | `0xC6` [reserved] | `0xD6` [reserved] | `0xE6` Known to be Compromised | `0xF6` Off-Chain Expiry or Limit Reached |
| `0x*7` | `0x07` [reserved] | `0x17` [reserved] | `0x27` [reserved] | `0x37` [reserved] | `0x47` [reserved] | `0x57` [reserved] | `0x67` [reserved] | `0x77` [reserved] | `0x87` [reserved] | `0x97` [reserved] | `0xA7` [reserved] | `0xB7` [reserved] | `0xC7` [reserved] | `0xD7` [reserved] | `0xE7` [reserved] | `0xF7` [reserved] |
| `0x*8` | `0x08` Duplicate, Unnecessary, or Inapplicable | `0x18` Not Applicable to Current State | `0x28` Duplicate, Conflict, or Collision | `0x38` Already Voted | `0x48` Already Done | `0x58` Funds Not Required | `0x68` [reserved] | `0x78` [reserved] | `0x88` [reserved] | `0x98` [reserved] | `0xA8` App-Specific Inapplicable Condition | `0xB8` [reserved] | `0xC8` [reserved] | `0xD8` [reserved] | `0xE8` Already Signed or Not Encrypted | `0xF8` Duplicate Off-Chain Request |
| `0x*9` | `0x09` [reserved] | `0x19` [reserved] | `0x29` [reserved] | `0x39` [reserved] | `0x49` [reserved] | `0x59` [reserved] | `0x69` [reserved] | `0x79` [reserved] | `0x89` [reserved] | `0x99` [reserved] | `0xA9` [reserved] | `0xB9` [reserved] | `0xC9` [reserved] | `0xD9` [reserved] | `0xE9` [reserved] | `0xF9` [reserved] |
| `0x*A` | `0x0A` [reserved] | `0x1A` [reserved] | `0x2A` [reserved] | `0x3A` [reserved] | `0x4A` [reserved] | `0x5A` [reserved] | `0x6A` [reserved] | `0x7A` [reserved] | `0x8A` [reserved] | `0x9A` [reserved] | `0xAA` [reserved] | `0xBA` [reserved] | `0xCA` [reserved] | `0xDA` [reserved] | `0xEA` [reserved] | `0xFA` [reserved] |
| `0x*B` | `0x0B` [reserved] | `0x1B` [reserved] | `0x2B` [reserved] | `0x3B` [reserved] | `0x4B` [reserved] | `0x5B` [reserved] | `0x6B` [reserved] | `0x7B` [reserved] | `0x8B` [reserved] | `0x9B` [reserved] | `0xAB` [reserved] | `0xBB` [reserved] | `0xCB` [reserved] | `0xDB` [reserved] | `0xEB` [reserved] | `0xFB` [reserved] |
| `0x*C` | `0x0C` [reserved] | `0x1C` [reserved] | `0x2C` [reserved] | `0x3C` [reserved] | `0x4C` [reserved] | `0x5C` [reserved] | `0x6C` [reserved] | `0x7C` [reserved] | `0x8C` [reserved] | `0x9C` [reserved] | `0xAC` [reserved] | `0xBC` [reserved] | `0xCC` [reserved] | `0xDC` [reserved] | `0xEC` [reserved] | `0xFC` [reserved] |
| `0x*D` | `0x0D` [reserved] | `0x1D` [reserved] | `0x2D` [reserved] | `0x3D` [reserved] | `0x4D` [reserved] | `0x5D` [reserved] | `0x6D` [reserved] | `0x7D` [reserved] | `0x8D` [reserved] | `0x9D` [reserved] | `0xAD` [reserved] | `0xBD` [reserved] | `0xCD` [reserved] | `0xDD` [reserved] | `0xED` [reserved] | `0xFD` [reserved] |
| `0x*E` | `0x0E` [reserved] | `0x1E` [reserved] | `0x2E` [reserved] | `0x3E` [reserved] | `0x4E` [reserved] | `0x5E` [reserved] | `0x6E` [reserved] | `0x7E` [reserved] | `0x8E` [reserved] | `0x9E` [reserved] | `0xAE` [reserved] | `0xBE` [reserved] | `0xCE` [reserved] | `0xDE` [reserved] | `0xEE` [reserved] | `0xFE` [reserved] |
| `0x*F` | `0x0F` Informational or Metadata | `0x1F` Permission Details or Control Conditions | `0x2F` Matching Meta or Info | `0x3F` Negotiation Rules or Participation Info | `0x4F` Availability Rules or Info (ex. time since or until) | `0x5F` Token or Financial Information | `0x6F` [reserved] | `0x7F` [reserved] | `0x8F` [reserved] | `0x9F` [reserved] | `0xAF` App-Specific Meta or Info | `0xBF` [reserved] | `0xCF` [reserved] | `0xDF` [reserved] | `0xEF` Cryptography, ID, or Proof Metadata | `0xFF` Off-Chain Info or Meta |
### Example Function Change
```solidity
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"44"; } // 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
0x44 = Not Yet Available
Exchange
AwesomeCoin DEX TraderBot
+ + +
| | buy(AwesomeCoin) |
| | <------------------------+
| buy() | |
| <---------------------+ |
| | |
| Status [0x44] | |
+---------------------> | Status [0x44] |
| +------------------------> |
| | |
| | isDoneYet() |
| | <------------------------+
| | |
| | Status [0x44] |
| +------------------------> |
| | |
| | |
| 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
Status codes are encoded as a `byte`. Hex values break nicely into high and low nibbles: `category` and `reason`. For instance, `0x01` stands for general success (ie: `true`) and `0x00` for general failure (ie: `false`).
As a general approach, all even numbers are blocking conditions (where the receiver does not have control), and odd numbers are nonblocking (the receiver is free to contrinue as they wish). This aligns both a simple bit check with the common encoding of Booleans.
`bytes1` is very lightweight, portable, easily interoperable with `uint8`, cast from `enum`s, 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 interpreted 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 necessarily. This can lead to paradoxical results (ex `0x00` and `0x01` together), or greater resources allocated to interpreting 256<sup>4</sup> (4.3 billion) permutations.
### Multiple Returns
While there may be cases where packing a byte array of status codes 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 tuples.
### 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. Status code `0x10` is just as comfortable as HTTP 401, for example.
#### Localizations
One commonly requested application of this spec is human-readable translations of codes. This has been moved to its own proposal: [ERC-1444](./eip-1444.md), primarily due to a desire to keep both specs focused.
### Extensibility
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.
### Beyond Errors
This spec is intended to be much more than a set of common errors. One design goal is to enable easier contract-to-contract communication, protocols built on top of status codes, and flows that cross off-chain. Many of these cases include either expected kinds of exception state (as opposed to true errors), neutral states, time logic, and various successes.
Just like how HTTP 200 has a different meaning from HTTP 201, ERC-1066 status codes can relay information between contract beyond simply pass or fail. They can be thought of as the edges in a graph that has smart contracts as nodes.
### Fully `revert`able
_This spec is fully compatible with `revert`-with-reason and does not intend to supplant it in any way._ Both by reverting with a common code, the developer can determine what went wrong from a set of known error states.
Further, by leveraging ERC-1066 and a translation table (such as in ERC-1444) in conjunction, developers and end users alike can receive fully automated human-readable error messages in the language and phrasing of their choice.
### 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
```solidity
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.
```solidity
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, and also saves gas (fewer operations required).
```solidity
enum Sleep {
Awake,
Asleep,
BedOccupied,
WindingDown
}
// 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:
* [Source Code](https://github.com/fission-suite/fission-codes/)
* [Package on npm](https://www.npmjs.com/package/fission-codes/)
## Copyright
Copyright and related rights waived via [CC0](../LICENSE.md).