diff --git a/contracts/FISSION.sol b/contracts/FISSION.sol index 991eaa0..cce5719 100644 --- a/contracts/FISSION.sol +++ b/contracts/FISSION.sol @@ -3,7 +3,17 @@ pragma solidity ^0.5.0; import { LocalizationPreferences} from "/ethereum-localized-messaging/contracts/LocalizationPreferences.sol"; import { FissionLocalization } from "./localization/FissionLocalization.sol"; +/** + * @title The FISSION Status Code Library + * + * @dev Implementation of broadly applicable status codes for smart contracts. + * https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1066.md + */ library FISSION { + + ///////////////////////////// Decomposed Enums ///////////////////////////// + + /// @dev The category component of an ERC-1066 status code (ie: the columns) enum Category { Generic, Permission, @@ -27,6 +37,7 @@ library FISSION { OffChain } + /// @dev The reason component of an ERC-1066 status code (ie: the rows) enum Reason { Failure, Success, @@ -52,7 +63,12 @@ library FISSION { Informational } + //////////////////////////// Simple Status Enum //////////////////////////// + + /// @dev ERC-1066 status codes encoded as human-readable enums enum Status { + + // 0x0* Failure, Success, AwatingOthers, @@ -70,6 +86,7 @@ library FISSION { RESERVEDx0E, Informational, + // 0x1* Disallowed_Stop, Allowed_Go, AwaitingOthersPermission, @@ -87,6 +104,7 @@ library FISSION { RESERVEDx1E, PermissionDetails_ControlConditions, + // 0x2* NotFound_Unequal_OutOfRange, Found_Equal_InRange, AwaitingMatch, @@ -104,6 +122,7 @@ library FISSION { RESERVEDx2E, MatchingInformation, + // 0x3* SenderDisagrees_Nay, SenderAgrees_Yea, AwaitingRatification, @@ -121,6 +140,7 @@ library FISSION { RESERVEDx3E, NegotiationRules_ParticipationInformation, + // 0x4* Unavailable, Available, Paused, @@ -138,6 +158,7 @@ library FISSION { RESERVEDx4E, AvailabilityRules_Information, + // 0x5* TransferFailed, TransferSuccessful, AwaitingPaymentFromOthers, @@ -155,6 +176,7 @@ library FISSION { RESERVEDx5E, FinancialInformation, + // 0x6* RESERVEDx60, RESERVEDx61, RESERVEDx62, @@ -172,6 +194,7 @@ library FISSION { RESERVEDx6E, RESERVEDx6F, + // 0x7* RESERVEDx70, RESERVEDx71, RESERVEDx72, @@ -189,6 +212,7 @@ library FISSION { RESERVEDx7E, RESERVEDx7F, + // 0x8* RESERVEDx80, RESERVEDx81, RESERVEDx82, @@ -206,6 +230,7 @@ library FISSION { RESERVEDx8E, RESERVEDx8F, + // 0x9* RESERVEDx90, RESERVEDx91, RESERVEDx92, @@ -223,6 +248,7 @@ library FISSION { RESERVEDx9E, RESERVEDx9F, + // 0xA* ApplicationSpecificFailure, ApplicationSpecificSuccess, ApplicationSpecificAwatingOthers, @@ -240,6 +266,7 @@ library FISSION { RESERVEDxAE, ApplicationSpecificInformational, + // 0xB* RESERVEDxB0, RESERVEDxB1, RESERVEDxB2, @@ -257,6 +284,7 @@ library FISSION { RESERVEDxBE, RESERVEDxBF, + // 0xC* RESERVEDxC0, RESERVEDxC1, RESERVEDxC2, @@ -274,6 +302,7 @@ library FISSION { RESERVEDxCE, RESERVEDxCF, + // 0xD* RESERVEDxD0, RESERVEDxD1, RESERVEDxD2, @@ -291,6 +320,7 @@ library FISSION { RESERVEDxDE, RESERVEDxDF, + // 0xE* DecryptFailure, DecryptSuccess, AwaitingOtherSignaturesOrKeys, @@ -308,7 +338,7 @@ library FISSION { RESERVEDxEE, Cryptography_ID_ProofMetadata, - + // 0xF* OffChainFailure, OffChainSuccess, AwatingOffChainProcess, @@ -327,85 +357,467 @@ library FISSION { OffChainInformation } + ////////////////////////////// Construction //////////////////////////////// + + /** + * @dev Coerce a status enum into a standard status byte + * + * @param statusEnum Status enum tag + * @return status Binary ERC-1066 status code + */ function code(Status statusEnum) public pure returns (byte status) { return byte(uint8(statusEnum)); } - function code(byte category, byte reason) public pure returns (byte status) { + /** + * @dev Construct a status code from a category and reason. + * + * @param category Category nibble + * @param reason Reason nibble + * @return status Binary ERC-1066 status code + */ + function code(byte category, byte reason) + public + pure + returns (byte status) + { return (category << 4) | (byte(0x0F) & reason); } - function code(uint8 category, uint8 reason) public pure returns (byte status) { + /** + * @dev Construct a status code from a category and reason. + * + * @param category The category + * @param reason The reason + * @return status Binary ERC-1066 status code + */ + function code(uint8 category, uint8 reason) + public + pure + returns (byte status) + { return byte(uint8((category << 4) + reason)); } - function code(Category category, Reason reason) public pure returns (byte status) { + /** + * @dev Construct a status code from category and reason enums + * + * @param category Category nibble + * @param reason Reason nibble + * @return status Binary ERC-1066 status code + */ + function code(Category category, Reason reason) + public + pure + returns (byte status) + { return code(uint8(category), uint8(reason)); } + /** + * @dev Construct an application-specific status code + * + * @param appReason Application-specific reason nibble + * @return status Binary ERC-1066 status code + */ + function appCode(byte appReason) public pure returns (byte status) { + return (byte(0xA0) | appReason); + } + + /** + * @dev Construct an application-specific status code + * + * @param appReason Application-specific reason + * @return status Binary ERC-1066 status code + */ function appCode(uint8 appReason) public pure returns (byte status) { - return byte(uint8(160 + appReason)); + return byte(160 + appReason); } - // Get nibbles + /** + * @dev Construct an application-specific status code + * + * @param appReason Application-specific reason enum + * @return status Binary ERC-1066 status code + */ + function appCode(Reason appReason) public pure returns (byte status) { + return appCode(uint8(appReason)); + } - function categoryOf(byte status) public pure returns (uint8 category) { - return (uint8(status >> 4)); + /////////////////////////////// Get Nibbles //////////////////////////////// + + /** + * @dev Extract the category from a status code + * + * @param status Binary ERC-1066 status code + * @return category Category nibble + */ + function categoryOf(byte status) public pure returns (byte category) { + return status >> 4; } - function reasonOf(byte status) public pure returns (uint8 reason) { - return uint8(status & 0x0F); + /** + * @dev Extract the category from a status code enum + * + * @param status Status enum + * @return category Category nibble + */ + function categoryOf(Status status) public pure returns (byte category) { + return categoryOf(byte(uint8(status))); } - // Localization + /** + * @dev Extract the reason from a status code + * + * @param status Binary ERC-1066 status code + * @return reason Reason nibble + */ + function reasonOf(byte status) public pure returns (byte reason) { + return status & 0x0F; + } - function localizeBy(byte status, LocalizationPreferences prefs) view public returns (bool found, string memory _msg) { + /** + * @dev Extract the reason from a status code enum + * + * @param status Status enum + * @return reason Reason nibble + */ + function reasonOf(Status status) public pure returns (byte reason) { + return reasonOf(byte(uint8(status))); + } + + /** + * @dev Decompose a status code into its category and reason nibbles + * + * @param status Binary ERC-1066 status code + * @return { + * "category": "Category nibble", + * "reason": "Reason nibble" + * } + */ + function split(byte status) public returns (byte category, byte reason) { + return (categoryOf(status), reasonOf(status)); + } + + ////////////////////////////// Localization //////////////////////////////// + + /** + * @dev Lookup an ERC-1444 localization for a particular status code + * + * @param status Binary ERC-1066 status code + * @param prefs The localization registry / proxy contract + * @return { + * "found": "If the loicalization string was found (`false` if a fallback was used)", + * "message": "The localization string" + * } + */ + function localizeBy(byte status, LocalizationPreferences prefs) + view + public + returns (bool found, string memory message) + { return prefs.textFor(status); } - // Check common statuses + ////////////////////////// Check Common Statuses /////////////////////////// - function isOk(byte status) public pure returns (bool) { + /** + * @dev Check if a status code is non-blocking (ie: an odd number) + * + * @param status Binary ERC-1066 status code + * @return okay A boolean representing if the status code + * is okay / nonblocking + */ + function isOk(byte status) public pure returns (bool okay) { return (uint8(status) % 2) == 1; } - function isBlocking(byte status) public pure returns (bool) { + /** + * @dev Check if a status code is blocking (ie: an even number) + * + * @param status Binary ERC-1066 status code + * @return blocking A boolean representing if the status code is blocking + */ + function isBlocking(byte status) public pure returns (bool blocking) { return !isOk(status); } - function isSuccess(byte status) public pure returns (bool) { - return reasonOf(status) == 1; + /** + * @dev Check if a status code represents success (ie: 0x*1) + * + * @param status Binary ERC-1066 status code + * @return successful A boolean representing if the status code + * represents success + */ + function isSuccess(byte status) public pure returns (bool successful) { + return reasonOf(status) == 0x01; + } + + /** + * @dev Check if a status code represents failure (ie: 0x*0) + * + * @param status Binary ERC-1066 status code + * @return failure A boolean representing if the status code + * represents failure + */ + function isFailure(byte status) public pure returns (bool failure) { + return reasonOf(status) == 0x00; } - function isFailure(byte status) public pure returns (bool) { - return reasonOf(status) == 0; + /** + * @dev Check if a status code belongs to a particular category + * + * @param status Binary ERC-1066 status code + * @param category Category nibble + * @return belongs A boolean representing if the status code belongs to + * the target category + */ + function isCategory(byte status, byte category) + public + pure + returns (bool belongs) + { + return categoryOf(status) == category; } - // `require`s + /** + * @dev Check if a status code belongs to a particular category + * + * @param status Binary ERC-1066 status code + * @param category Category enum + * @return belongs A boolean representing if the status code belongs to + * the target category + */ + function isCategory(byte status, Category category) + public + pure + returns (bool belongs) + { + return categoryOf(status) == byte(uint8(category)); + } + /** + * @dev Check if a Status enum belongs to a particular category + * + * @param status Status enum + * @param category Category enum + * @return belongs A boolean representing if the status enum belongs to + * the target category + */ + function isCategory(Status status, Category category) + public + pure + returns (bool belongs) + { + return categoryOf(status) == byte(uint8(category)); + } + + /** + * @dev Check if a status code has a particular reason + * + * @param status Binary ERC-1066 status code + * @param reason Reason nibble + * @return belongs A boolean representing if the status code has + * the target reason + */ + function isReason(byte status, byte reason) + public + pure + returns (bool belongs) + { + return reasonOf(status) == reason; + } + + /** + * @dev Check if a status code belongs to a particular category + * + * @param status Binary ERC-1066 status code + * @param reason Reason enum + * @return belongs A boolean representing if the status code has + * the target reason + */ + function isReason(byte status, Reason reason) + public + pure + returns (bool belongs) + { + return reasonOf(status) == byte(uint8(reason)); + } + + /** + * @dev Check if a Status enum has a particular reason + * + * @param status Status enum + * @param reason Reason enum + * @return belongs A boolean representing if the status code has + * the target reason + */ + function isReason(Status status, Reason reason) + public + pure + returns (bool belongs) + { + return reasonOf(status) == byte(uint8(reason)); + } + + ///////////////////////////////// Requires ///////////////////////////////// + + /** + * @dev Require that a status code be nonblocking, otherwise `revert` + * + * @param status Binary ERC-1066 status code + */ function requireOk(byte status) public pure { require(isOk(status), "Blocking status code"); // TODO: use translation singleton } + /** + * @dev Require that a status code be nonblocking, + * otherwise `revert` with message + * + * @param status Binary ERC-1066 status code + * @param message Revert message + */ function requireOk(byte status, string memory message) public pure { require(isOk(status), message); } + /** + * @dev Require that a status code be nonblocking, + * otherwise `revert` with an ERC-1444 automatically localized message + * + * @param status Binary ERC-1066 status code + * @param prefs Localization preference registry + */ function requireOk(byte status, LocalizationPreferences prefs) public view { (bool _, string memory message) = localizeBy(status, prefs); requireOk(status, message); } + /** + * @dev Require that a status code represent success, otherwise `revert` + * + * @param status Binary ERC-1066 status code + */ function requireSuccess(byte status) public pure { require(isSuccess(status), "Unsuccessful status code reason"); } + /** + * @dev Require that a status code represent success, + * otherwise `revert` with message + * + * @param status Binary ERC-1066 status code + * @param message Revert message + */ function requireSuccess(byte status, string memory message) public pure { require(isSuccess(status), message); } - function requireSuccess(byte status, LocalizationPreferences prefs) public view { + /** + * @dev Require that a status code represent success, + * otherwise `revert` with an ERC-1444 automatically localized message + * + * @param status Binary ERC-1066 status code + * @param prefs Localization preference registry + */ + function requireSuccess(byte status, LocalizationPreferences prefs) + public + view + { (bool _, string memory message) = localizeBy(status, prefs); requireSuccess(status, message); } + + /** + * @dev Require that a status code belongs to a particular category, + * otherwise `revert` + * + * @param status Binary ERC-1066 status code + * @param category Required category nibble + */ + function requireCategory(byte status, byte category) public view { + require(isCategory(status, category)); + } + + /** + * @dev Require that a status code belongs to a particular category, + * otherwise `revert` with message + * + * @param status Binary ERC-1066 status code + * @param category Required category nibble + * @param message Revert message + */ + function requireCategory(byte status, byte category, string memory message) + public + view + { + require(isCategory(status, category), message); + } + + /** + * @dev Require that a status code belongs to a particular category, + * otherwise `revert` with an ERC-1444 automatically localized message + * + * @param status Binary ERC-1066 status code + * @param category Required category nibble + * @param prefs Localization preference registry + */ + function requireCategory( + byte status, + byte category, + LocalizationPreferences prefs + ) + public + view + { + (bool _, string memory message) = localizeBy(status, prefs); + requireCategory(status, category, message); + } + + /** + * @dev Require that a status code has a particular reason, + * otherwise `revert` + * + * @param status Binary ERC-1066 status code + * @param reason Required reason nibble + */ + function requireReason(byte status, byte reason) public view { + require(isReason(status, reason)); + } + + /** + * @dev Require that a status code has a particular reason, + * otherwise `revert` with message + * + * @param status Binary ERC-1066 status code + * @param reason Required reason nibble + * @param message Revert message + */ + function requireReason(byte status, byte reason, string memory message) + public + view + { + require(isReason(status, reason), message); + } + + /** + * @dev Require that a status code has a particular reason, + * otherwise `revert` with an ERC-1444 automatically localized message + * + * @param status Binary ERC-1066 status code + * @param reason Required reason nibble + * @param prefs Localization preference registry + */ + function requireReason( + byte status, + byte reason, + LocalizationPreferences prefs + ) + public + view + { + (bool _, string memory message) = localizeBy(status, prefs); + requireReason(status, reason, message); + } } diff --git a/lib/fission.js b/lib/fission.js index 1cd601e..371af01 100644 --- a/lib/fission.js +++ b/lib/fission.js @@ -4,7 +4,7 @@ const { toHexDigit } = require('./fission/hex'); // Mappings -const combine = ({categoryId, reasonId}) => (categoryId * 16) + reasonId; +const combine = ({categoryId, reasonId}) => (categoryId * 0x10) + reasonId; const split = (codeNum) => { if (!Number.isInteger(codeNum)) throw TypeError(`${codeNum} is not a number`); @@ -20,41 +20,351 @@ const split = (codeNum) => { const humanize = ({categoryId, reasonId}) => { return { - category: Category.CATEGORY[categoryId], - reason: Reason.REASON[reasonId] + category: Category.CATEGORY_NAMES[categoryId], + reason: Reason.REASON_NAMES[reasonId] }; }; +const dehumanize = ({category, reason}) => { + return { + categoryId: Category.CATEGORIES[category], + reasonId: Reason.REASONS[reason] + }; +}; + +const categoryIdOf = (codeNum) => split(codeNum).categoryId; +const categoryOf = (codeNum) => Category.CATEGORY_NAMES[categoryIdOf(codeNum)]; + +const reasonIdOf = (codeNum) => split(codeNum).reasonId; +const reasonOf = (codeNum) => Reason.REASON_NAMES[reasonIdOf(codeNum)]; + // Formatters const toNumber = ({category, reason}) => { - const categoryId = Category.CATEGORY.indexOf(category); - if (categoryId < 0) throw Category.badLookup(category); + const categoryId = Category.CATEGORIES[category]; + if (categoryId === undefined) throw Category.badLookup(category); - const reasonId = Reason.REASON.indexOf(reason); - if (reasonId < 0) throw Reason.badLookup(reason); + const reasonId = Reason.REASON[reason]; + if (reasonId === undefined) throw Reason.badLookup(reason); return combine({categoryId, reasonId}); }; -const toHexString = ({category, reason}) => { - const catNum = Category.CATEGORY.indexOf(category); - const reasonNum = Reason.REASON.indexOf(reason); - - return `0x${toHexDigit(catNum)}${toHexDigit(reasonNum)}`; -}; +const toHexString = ({categoryId, reasonId}) => + `0x${toHexDigit(categoryId)}${toHexDigit(reasonId)}`; const hexifyCode = (codeNum) => { const {categoryId, reasonId} = split(codeNum); return `0x${toHexDigit(categoryId)}${toHexDigit(reasonId)}`; }; +// Enum + +const STATUSES = Object.freeze({ + // 0x0* + FAILURE: 0x00, + SUCCESS: 0x01, + AWATING_OTHERS: 0x02, + ACCEPTED: 0x03, + LOWER_LIMIT: 0x04, + RECIEVER_ACTION_REQUESTED: 0x05, + UPPER_LIMIT: 0x06, + RESERVEDx07: 0x07, + INAPPLICABLE: 0x08, + RESERVEDx09: 0x09, + RESERVEDx0A: 0xA0, + RESERVEDx0B: 0x0B, + RESERVEDx0C: 0x0C, + RESERVEDx0D: 0x0D, + RESERVEDx0E: 0x0E, + INFORMATIONAL: 0x0F, + + // 0x1* + DISALLOWED_STOP: 0x10, + ALLOWED_GO: 0x11, + AWAITING_OTHERS_PERMISSION: 0x12, + PERMISSION_REQUESTED: 0x13, + TOO_OPEN_INSECURE: 0x14, + NEEDS_YOUR_PERMISSION_REQUEST_FOR_CONTINUATION: 0x15, + REVOKED: 0x16, + RESERVEDx17: 0x17, + NOT_APPLICATABLE_TO_CURRENT_STATE: 0x18, + RESERVEDx19: 0x19, + RESERVEDx1A: 0x1A, + RESERVEDx1B: 0x1B, + RESERVEDx1C: 0x1C, + RESERVEDx1D: 0x1D, + RESERVEDx1E: 0x1E, + PERMISSION_DETAILS_CONTROL_CONDITIONS: 0x1F, + + // 0x2* + NOT_FOUND_UNEQUAL_OUT_OF_RANGE: 0x20, + FOUND_EQUAL_IN_RANGE: 0x21, + AWAITING_MATCH: 0x22, + MATCH_REQUEST_SENT: 0x23, + BELOW_RANGE_UNDERFLOW: 0x24, + REQUEST_FOR_MATCH: 0x25, + ABOVE_RANGE_OVERFLOW: 0x26, + RESERVEDx27: 0x27, + DUPLICATE_CONFLICT_COLLISION: 0x28, + RESERVEDx29: 0x29, + RESERVEDx2A: 0x2A, + RESERVEDx2B: 0x2B, + RESERVEDx2C: 0x2C, + RESERVEDx2D: 0x2D, + RESERVEDx2E: 0x2E, + MATCHING_INFORMATION: 0x2F, + + // 0x3* + SENDER_DISAGREES_NAY: 0x30, + SENDER_AGREES_YEA: 0x31, + AWAITING_RATIFICATION: 0x32, + OFFER_SENT_VOTED: 0x33, + QUORUM_NOT_REACHED: 0x34, + RECEIVERS_RATIFICATION_REQUESTED: 0x35, + OFFER_OR_VOTE_LIMIT_REACHED: 0x36, + RESERVEDx37: 0x37, + ALREADY_VOTED: 0x38, + RESERVEDx39: 0x39, + RESERVEDx3A: 0x3A, + RESERVEDx3B: 0x3B, + RESERVEDx3C: 0x3C, + RESERVEDx3D: 0x3D, + RESERVEDx3E: 0x3E, + NEGOTIATION_RULES_PARTICIPATION_INFORMATION: 0x3F, + + // 0x4* + UNAVAILABLE: 0x40, + AVAILABLE: 0x41, + PAUSED: 0x42, + QUEUED: 0x43, + NOT_AVAILABLE_YET: 0x44, + AWAITING_YOUR_AVAILABILITY: 0x45, + EXPIRED: 0x46, + RESERVEDx47: 0x47, + ALREADY_DONE: 0x48, + RESERVEDx49: 0x49, + RESERVEDx4A: 0x4A, + RESERVEDx4B: 0x4B, + RESERVEDx4C: 0x4C, + RESERVEDx4D: 0x4D, + RESERVEDx4E: 0x4E, + AVAILABILITY_RULES_INFORMATION: 0x4F, + + // 0x5* + TRANSFER_FAILED: 0x50, + TRANSFER_SUCCESSFUL: 0x51, + AWAITING_PAYMENT_FROM_OTHERS: 0x52, + HOLD_ESCROW: 0x53, + INSUFFICIENT_FUNDS: 0x54, + FUNDS_REQUESTED: 0x55, + TRANSFER_VOLUME_EXCEEDED: 0x56, + RESERVEDx57: 0x57, + FUNDS_NOT_REQUIRED: 0x58, + RESERVEDx59: 0x59, + RESERVEDx5A: 0x5A, + RESERVEDx5B: 0x5B, + RESERVEDx5C: 0x5C, + RESERVEDx5D: 0x5D, + RESERVEDx5E: 0x5E, + FINANCIAL_INFORMATION: 0x5F, + + // 0x6* + RESERVEDx60: 0x60, + RESERVEDx61: 0x61, + RESERVEDx62: 0x62, + RESERVEDx63: 0x63, + RESERVEDx64: 0x64, + RESERVEDx65: 0x65, + RESERVEDx66: 0x66, + RESERVEDx67: 0x67, + RESERVEDx68: 0x68, + RESERVEDx69: 0x69, + RESERVEDx6A: 0x6A, + RESERVEDx6B: 0x6B, + RESERVEDx6C: 0x6C, + RESERVEDx6D: 0x6D, + RESERVEDx6E: 0x6E, + RESERVEDx6F: 0x6F, + + // 0x7* + RESERVEDx70: 0x70, + RESERVEDx71: 0x71, + RESERVEDx72: 0x72, + RESERVEDx73: 0x73, + RESERVEDx74: 0x74, + RESERVEDx75: 0x75, + RESERVEDx76: 0x76, + RESERVEDx77: 0x77, + RESERVEDx78: 0x78, + RESERVEDx79: 0x79, + RESERVEDx7A: 0x7A, + RESERVEDx7B: 0x7B, + RESERVEDx7C: 0x7C, + RESERVEDx7D: 0x7D, + RESERVEDx7E: 0x7E, + RESERVEDx7F: 0x7F, + + // 0x8* + RESERVEDx80: 0x80, + RESERVEDx81: 0x81, + RESERVEDx82: 0x82, + RESERVEDx83: 0x83, + RESERVEDx84: 0x84, + RESERVEDx85: 0x85, + RESERVEDx86: 0x86, + RESERVEDx87: 0x87, + RESERVEDx88: 0x88, + RESERVEDx89: 0x89, + RESERVEDx8A: 0x8A, + RESERVEDx8B: 0x8B, + RESERVEDx8C: 0x8C, + RESERVEDx8D: 0x8D, + RESERVEDx8E: 0x8E, + RESERVEDx8F: 0x8F, + + // 0x9* + RESERVEDx90: 0x90, + RESERVEDx91: 0x91, + RESERVEDx92: 0x92, + RESERVEDx93: 0x93, + RESERVEDx94: 0x94, + RESERVEDx95: 0x95, + RESERVEDx96: 0x96, + RESERVEDx97: 0x97, + RESERVEDx98: 0x98, + RESERVEDx99: 0x99, + RESERVEDx9A: 0x9A, + RESERVEDx9B: 0x9B, + RESERVEDx9C: 0x9C, + RESERVEDx9D: 0x9D, + RESERVEDx9E: 0x9E, + RESERVEDx9F: 0x9F, + + // 0xA* + APPLICATION_SPECIFIC_FAILURE: 0xA0, + APPLICATION_SPECIFIC_SUCCESS: 0xA1, + APPLICATION_SPECIFIC_AWATING_OTHERS: 0xA2, + APPLICATION_SPECIFIC_ACCEPTED: 0xA3, + APPLICATION_SPECIFIC_LOWER_LIMIT: 0xA4, + APPLICATION_SPECIFIC_RECIEVER_ACTION_REQUESTED: 0xA5, + APPLICATION_SPECIFIC_UPPER_LIMIT: 0xA6, + RESERVEDxA7: 0xA7, + APPLICATION_SPECIFIC_INAPPLICABLE: 0xA8, + RESERVEDxA9: 0xA9, + RESERVEDxAA: 0xAA, + RESERVEDxAB: 0xAB, + RESERVEDxAC: 0xAC, + RESERVEDxAD: 0xAD, + RESERVEDxAE: 0xAE, + APPLICATION_SPECIFIC_INFORMATIONAL: 0xAF, + + // 0xB* + RESERVEDxB0: 0xB0, + RESERVEDxB1: 0xB1, + RESERVEDxB2: 0xB2, + RESERVEDxB3: 0xB3, + RESERVEDxB4: 0xB4, + RESERVEDxB5: 0xB5, + RESERVEDxB6: 0xB6, + RESERVEDxB7: 0xB7, + RESERVEDxB8: 0xB8, + RESERVEDxB9: 0xB9, + RESERVEDxBA: 0xBA, + RESERVEDxBB: 0xBB, + RESERVEDxBC: 0xBC, + RESERVEDxBD: 0xBD, + RESERVEDxBE: 0xBE, + RESERVEDxBF: 0xBF, + + // 0xC* + RESERVEDxC0: 0xC0, + RESERVEDxC1: 0xC1, + RESERVEDxC2: 0xC2, + RESERVEDxC3: 0xC3, + RESERVEDxC4: 0xC4, + RESERVEDxC5: 0xC5, + RESERVEDxC6: 0xC6, + RESERVEDxC7: 0xC7, + RESERVEDxC8: 0xC8, + RESERVEDxC9: 0xC9, + RESERVEDxCA: 0xCA, + RESERVEDxCB: 0xCB, + RESERVEDxCC: 0xCC, + RESERVEDxCD: 0xCD, + RESERVEDxCE: 0xCE, + RESERVEDxCF: 0xCF, + + // 0xD* + RESERVEDxD0: 0xD0, + RESERVEDxD1: 0xD1, + RESERVEDxD2: 0xD2, + RESERVEDxD3: 0xD3, + RESERVEDxD4: 0xD4, + RESERVEDxD5: 0xD5, + RESERVEDxD6: 0xD6, + RESERVEDxD7: 0xD7, + RESERVEDxD8: 0xD8, + RESERVEDxD9: 0xD9, + RESERVEDxDA: 0xDA, + RESERVEDxDB: 0xDB, + RESERVEDxDC: 0xDC, + RESERVEDxDD: 0xDD, + RESERVEDxDE: 0xDE, + RESERVEDxDF: 0xDF, + + // 0xE* + DECRYPT_FAILURE: 0xE0, + DECRYPT_SUCCESS: 0xE1, + AWAITING_OTHER_SIGNATURES_OR_KEYS: 0xE2, + SIGNED: 0xE3, + UNSIGNED_UNTRUSTED: 0xE4, + SIGNATURE_REQUIRED: 0xE5, + KNOWN_TO_BE_COMPROMISED: 0xE6, + RESERVEDxE7: 0xE7, + ALREADY_SIGNED_NOT_ENCRYPTED: 0xE8, + RESERVEDxE9: 0xE9, + RESERVEDxEA: 0xEA, + RESERVEDxEB: 0xEB, + RESERVEDxEC: 0xEC, + RESERVEDxED: 0xED, + RESERVEDxEE: 0xEE, + CRYPTOGRAPHY_ID_PROOF_METADATA: 0xEF, + + // 0xF* + OFF_CHAIN_FAILURE: 0xF0, + OFF_CHAIN_SUCCESS: 0xF1, + AWATING_OFF_CHAIN_PROCESS: 0xF2, + OFF_CHAIN_PROCESS_STARTED: 0xF3, + OFF_CHAIN_SERVICE_UNREACHABLE: 0xF4, + OFF_CHAIN_ACTION_REQUIRED: 0xF5, + OFF_CHAIN_EXPIRY_LIMIT_REACHED: 0xF6, + RESERVEDxF7: 0xF7, + DUPLICATE_OFF_CHAIN_REQUEST: 0xF8, + RESERVEDxF9: 0xF9, + RESERVEDxFA: 0xFA, + RESERVEDxFB: 0xFB, + RESERVEDxFC: 0xFC, + RESERVEDxFD: 0xFD, + RESERVEDxFE: 0xFE, + OFF_CHAIN_INFORMATION: 0xFF +}); + + module.exports = { - CATEGORY: Category.CATEGORY, - REASON: Reason.REASON, + CATEGORIES: Category.CATEGORIES, + CATEGORY_NAMES: Category.CATEGORY_NAMES, + REASONS: Reason.REASONS, + REASON_NAMES: Reason.REASON_NAMES, + STATUSES, + categoryOf, + categoryIdOf, combine, + dehumanize, hexifyCode, humanize, + reasonOf, + reasonIdOf, split, toHexString, toNumber diff --git a/lib/fission/category.js b/lib/fission/category.js index 0e0e4a7..61e837c 100644 --- a/lib/fission/category.js +++ b/lib/fission/category.js @@ -1,44 +1,45 @@ const { toHexDigit } = require('./hex'); -const CATEGORY = [ - 'GENERIC', - 'PERMISSION', - 'FIND', - 'NEGOTIATION', - 'AVAILABILITY', - 'FINANCE', - - 'x60', - 'x70', - 'x80', - 'x90', - - 'APPLICATION_SPECIFIC', - - 'xB0', - 'xC0', - 'xD0', - - 'CRYPTOGRAPHY', - 'OFF_CHAIN' -]; - -const toId = (category) => { - const idx = CATEGORY.indexOf(category); - if (idx < 0) throw badLookup(category); - return idx; +const CATEGORIES = Object.freeze({ + GENERIC: 0x0, + PERMISSION: 0x1, + FIND: 0x2, + NEGOTIATION: 0x3, + AVAILABILITY: 0x4, + FINANCE: 0x5, + + x60: 0x6, + x70: 0x7, + x80: 0x8, + x90: 0x9, + + APPLICATION_SPECIFIC: 0xA, + + xB0: 0xB, + xC0: 0xC, + xD0: 0xD, + + CRYPTOGRAPHY: 0xE, + OFF_CHAIN: 0xF +}); + +const CATEGORY_NAMES = Object.freeze(Object.keys(CATEGORIES)); + +const toNumber = (name) => { + const id = CATEGORIES[name]; + if (id === undefined) throw badLookup(name); + return id * 0x10; }; -const toNumber = (category) => toId(category) * 16; - const toHexString = (num) => `0x${toHexDigit(num)}0`; const badLookup = (targetCategory) => Error(`${targetCategory} is not a valid ERC-1066 category`); module.exports = { - CATEGORY, + CATEGORIES, + CATEGORY_NAMES, toHexString, toNumber, - toId + badLookup }; diff --git a/lib/fission/reason.js b/lib/fission/reason.js index 9c8c1fd..f99d6ee 100644 --- a/lib/fission/reason.js +++ b/lib/fission/reason.js @@ -1,46 +1,46 @@ const { toHexDigit } = require('./hex'); -const REASON = [ - 'FAILURE', - 'SUCCESS', +const REASONS = Object.freeze({ + FAILURE: 0x00, + SUCCESS: 0x01, - 'AWAITING_OTHERS', - 'ACCEPTED', - 'LOWER_LIMIT', - 'ACTION_REQUESTED', - 'UPPER_LIMIT', + AWAITING_OTHERS: 0x02, + ACCEPTED: 0x03, + LOWER_LIMIT: 0x04, + ACTION_REQUESTED: 0x05, + UPPER_LIMIT: 0x06, - 'x06', - 'x07', + x07: 0x07, - 'INAPPLICABLE', + INAPPLICABLE: 0x08, - 'x09', - 'x0A', - 'x0B', - 'x0C', - 'x0D', - 'x0E', + x09: 0x09, + x0A: 0x0A, + x0B: 0x0B, + x0C: 0x0C, + x0D: 0x0D, + x0E: 0x0E, - 'INFORMATIONAL' -]; + INFORMATIONAL: 0x0F + }); -const toHexString = (num) => `0x0${toHexDigit(num)}`; +const REASON_NAMES = Object.freeze(Object.keys(REASONS)); -const toId = (reason) => { - const idx = REASON.indexOf(reason); - if (idx < 0) throw badLookup(reason); - return idx; +const toNumber = (name) => { + const id = REASONS[name]; + if (id === undefined) throw badLookup(name); + return id; }; -const toNumber = toId; +const toHexString = (num) => `0x0${toHexDigit(num)}`; const badLookup = (targetReason) => Error(`${targetReason} is not a valid ERC-1066 reason`); module.exports = { - REASON, + REASONS, + REASON_NAMES, + badLookup, toHexString, - toNumber, - toId + toNumber }; diff --git a/package.json b/package.json index a274d50..12998fd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "fission-codes", - "version": "1.0.0-rc1", + "version": "1.0.0-rc.2", "description": "Smart contract status codes and helpers", "keywords": [ "ethereum", @@ -19,15 +19,15 @@ "main": "lib/fission.js", "license": "Apache-2.0", "scripts": { + "coverage": "./node_modules/.bin/solidity-coverage", "pretest": "./ensure-ganache-running.sh || (npm run start:testrpc &)", + "start:testrpc": "ganache-cli -u 0", "test": "truffle test", "test:lint": "eslint -c .eslintrc . --color=true --quiet", "test:lint:fix": "eslint -c .eslintrc . --color=true --quiet --fix", "truffle:compile": "truffle compile", "truffle:debug": "truffle debug", - "truffle:migrate": "truffle migrate", - "start:testrpc": "ganache-cli -u 0", - "coverage": "./node_modules/.bin/solidity-coverage" + "truffle:migrate": "truffle migrate" }, "bugs": { "url": "https://github.com/fission-suite/fission-codes/issues" diff --git a/test/contracts/.tern-port b/test/contracts/.tern-port new file mode 100644 index 0000000..b8c6ea1 --- /dev/null +++ b/test/contracts/.tern-port @@ -0,0 +1 @@ +60672 \ No newline at end of file diff --git a/test/contracts/status.spec.js b/test/contracts/fission.spec.js similarity index 67% rename from test/contracts/status.spec.js rename to test/contracts/fission.spec.js index 0147fe6..9790c7e 100644 --- a/test/contracts/status.spec.js +++ b/test/contracts/fission.spec.js @@ -1,5 +1,6 @@ const { expect } = require('chai'); const { expectRevert } = require('../helpers'); +const fissionJS = require('../../lib/fission'); /* eslint-disable no-undef */ const FISSION = artifacts.require('FISSION'); @@ -19,14 +20,42 @@ contract('fission', () => { // eslint-disable-line no-undef registry = await LocalizationPreferences.new(localization.address); }); - // Having issues with overloaded functions - // - // describe('#code', () => { - // it('constructs a code out of numbers', async () => { - // const code = await fission.code(10, 6); - // expect(Number(code)).to.equal(0xA6); - // }); - // }); + describe('#code', () => { + describe('#code(bytes1,bytes1)', () => { + it('constructs a code out of numbers', async () => { + const code = await fission.methods['code(bytes1,bytes1)']('0x0A', '0x06'); + expect(Number(code)).to.equal(0xA6); + }); + }); + + describe('#code(uint8,uint8)', () => { + it('constructs a code out of numbers', async () => { + const code = await fission.methods['code(uint8,uint8)'](10, 6); + expect(Number(code)).to.equal(0xA6); + }); + }); + + // FIXME: Truffle seems to be struggling with enums in any representation + // + // describe('#code(Status)', () => { + // it('constructs a code out of a Status enum', async () => { + // const code = await fission.methods['code(FISSION.Status)'].call(0x08); + // console.log(JSON.stringify(code)); + // expect(Number(code)).to.equal(0x08); + // }); + // }); + + // describe('#code(Category,Reason)', () => { + // it('constructs a code out of Category and Reason enums', async () => { + // const code = await fission.methods['code(FISSION.Category,FISSION.Reason)']( + // fissionJS.CATEGORIES.FIND, + // fissionJS.REASONS.UPPER_LIMIT + // ); + + // expect(Number(code)).to.equal(0x26); + // }); + // }); + }); describe('#appCode', () => { it('prepends "A" to the reason', async () => { @@ -48,25 +77,32 @@ contract('fission', () => { // eslint-disable-line no-undef }); describe('#reasonOf', () => { - it('retuns the upper nibble', async () => { - const cat = await fission.reasonOf('0x01'); - expect(Number(cat)).to.equal(1); - }); + describe('#reasonOf(bytes1)', () => { + it('retuns the upper nibble', async () => { + const cat = await fission.methods['reasonOf(bytes1)']('0x01'); + expect(Number(cat)).to.equal(1); + }); - it('retuns nibbles above 9', async () => { - const cat = await fission.reasonOf('0x3B'); - expect(Number(cat)).to.equal(11); + it('retuns nibbles above 9', async () => { + const cat = await fission.methods['reasonOf(bytes1)']('0x3B'); + expect(Number(cat)).to.equal(11); + }); }); - }); - // Having issues with overloaded functions - // - // describe('#localizeBy', () => { - // it('looks up a translation', async () => { - // const [found, text] = await fission.localizeBy('0x14', registry.address); - // expect(text).to.equal(''); - // }); - // }); + // FIXME: Truffle seems to be struggling with enums in any representation + // + // describe('#reasonOf(Status)', () => { + // it('retuns the upper nibble', async () => { + // const cat = await fission.methods['reasonOf(FISSION.Status)'](fissionJS.STATUSES.SUCCESS); + // expect(Number(cat)).to.equal(1); + // }); + + // it('retuns nibbles above 9', async () => { + // const cat = await fission.methods['reasonOf(uint8)'](fissionJS.STATUSES.ALLOWED_GO); + // expect(Number(cat)).to.equal(11); + // }); + // }); + }); describe('#isOk', () => { context('lower nibble is odd', () => { diff --git a/test/contracts/phone.spec.js b/test/contracts/phone.spec.js index a4b8511..51b077c 100644 --- a/test/contracts/phone.spec.js +++ b/test/contracts/phone.spec.js @@ -1,4 +1,5 @@ const { expect } = require('chai'); +const fissionJS = require('../../lib/fission'); const Phone = artifacts.require('Phone'); // eslint-disable-line no-undef const FISSION = artifacts.require('FISSION'); // eslint-disable-line no-undef @@ -24,11 +25,11 @@ contract('Phone', async (addresses) => { // eslint-disable-line no-undef const { 0: code, 1: msg } = await alice.incoming.call('Hey'); message = msg; - reason = await fission.reasonOf(code); + reason = fissionJS.reasonIdOf(Number(code)); }); it('starts the call', () => { - expect(Number(reason)).to.equal(1); + expect(reason).to.equal(1); }); it('returns a friendly message', () => { @@ -39,15 +40,13 @@ contract('Phone', async (addresses) => { // eslint-disable-line no-undef context('not on contact list', () => { before(async () => { const { 0: code, 1: msg } = await bob.incoming.call('Hey'); - console.log(code); - console.log(msg); message = msg; - reason = await fission.reasonOf(code); + reason = fissionJS.reasonIdOf(Number(code)); }); it('goes to voicemail', () => { - expect(Number(reason)).to.equal(2); + expect(reason).to.equal(2); }); it('includes the voicemail message', () => { @@ -62,11 +61,11 @@ contract('Phone', async (addresses) => { // eslint-disable-line no-undef const { 0: code, 1: msg } = await alice.outgoing.call(bob.address, 'hello'); message = msg; - reason = await fission.reasonOf(code); + reason = fissionJS.reasonIdOf(Number(code)); }); it('does not start the call', () => { - expect(Number(reason)).to.equal(0); + expect(reason).to.equal(0); }); it('records a message', () => { @@ -80,12 +79,11 @@ contract('Phone', async (addresses) => { // eslint-disable-line no-undef const { 0: code, 1: msg } = await alice.outgoing.call(alice.address, 'hello'); message = msg; - reason = await fission.reasonOf(code); + reason = fissionJS.reasonIdOf(Number(code)); }); - it('starts the call', () => { - expect(Number(reason)).to.equal(1); + expect(reason).to.equal(1); }); it('returns a friendly message', () => { diff --git a/test/lib/fission.spec.js b/test/lib/fission.spec.js index 4a1231b..a0848fe 100644 --- a/test/lib/fission.spec.js +++ b/test/lib/fission.spec.js @@ -3,11 +3,18 @@ const { expect } = require('chai'); const { randomInRange } = require('../helpers'); const { - CATEGORY, - REASON, + CATEGORIES, + CATEGORY_NAMES, + REASONS, + REASON_NAMES, + categoryOf, + categoryIdOf, combine, + dehumanize, hexifyCode, humanize, + reasonOf, + reasonIdOf, split, toHexString, toNumber @@ -15,7 +22,18 @@ const { const hexFormat = /0x[0-9A-F]{2}/; -describe('status.js', () => { +describe('fission.js', () => { + const categoryId = randomInRange(0x0, 0xF); + const reasonId = randomInRange(0x0, 0xF); + + const decomposed = {categoryId, reasonId}; + const code = combine(decomposed); + + const names = { + category: CATEGORY_NAMES[categoryId], + reason: REASON_NAMES[reasonId] + }; + describe('#combine', () => { it('generates a number', () => { expect(combine({categoryId: 1, reasonId: 2})).to.be.a('number'); @@ -31,115 +49,149 @@ describe('status.js', () => { }); describe('#split', () => { - const decomposed = split(randomInRange(0, 256)); - it('has the correct keys', () => { expect(decomposed).to.have.all.keys('categoryId', 'reasonId'); }); describe('categoryId', () => { - const { categoryId } = decomposed; - it('is a single hex number', () => { expect(categoryId).to.be.within(0, 15); }); }); describe('reasonId', () => { - const { reasonId } = decomposed; - it('is a single hex number', () => { expect(reasonId).to.be.within(0, 15); }); }); }); - describe('#humanize', () => { - const categoryId = randomInRange(0, 15); - const reasonId = randomInRange(0, 15); + describe('projections', () => { + describe('reason', () => { + describe('#reasonOf', () => { + it('extracts the reason\'s name', () => { + expect(reasonOf(code)).to.equal(REASON_NAMES[reasonId]); + }); + }); + + describe('#reasonIdOf', () => { + it('extracts the reason nibble', () => { + expect(reasonIdOf(code)).to.equal(reasonId); + }); + }); + }); + + describe('category', () => { + describe('#categoryOf', () => { + it('extracts the category\'s name', () => { + expect(categoryOf(code)).to.equal(CATEGORY_NAMES[categoryId]); + }); + }); - const ids = { categoryId, reasonId }; + describe('#categoryIdOf', () => { + it('extracts the reason nibble', () => { + expect(categoryIdOf(code)).to.equal(categoryId); + }); + }); + }); + }); + + describe('#humanize', () => { + const humanized = humanize(decomposed); it('has a category string', () => { - expect(humanize(ids)).to.include.all.keys('category', 'reason'); + expect(humanized).to.include.all.keys('category', 'reason'); }); describe('category', () => { - const { category } = humanize(ids); + const { category } = humanized; it('is a string', () => { expect(category).to.be.a('string'); }); it('is the corresponding category enum', () => { - expect(category).to.equal(CATEGORY[categoryId]); + expect(category).to.equal(CATEGORY_NAMES[categoryId]); }); }); describe('reason', () => { - const { reason } = humanize(ids); + const { reason } = humanized; it('is a string', () => expect(reason).to.be.a('string')); it('is the corresponding reason enum', () => { - expect(reason).to.equal(REASON[reasonId]); + expect(reason).to.equal(REASON_NAMES[reasonId]); }); }); }); - describe('#toNumber', () => { - const categoryId = randomInRange(0, 15); - const reasonId = randomInRange(0, 15); + describe('#dehumanize', () => { + const humanized = humanize(decomposed); + const {category, reason} = humanized; + + const dehumanized = dehumanize(humanize(decomposed)); + const {categoryId, reasonId} = dehumanized; + + it('has a category string', () => { + expect(dehumanized).to.include.all.keys('categoryId', 'reasonId'); + }); - const decomposed = { - category: CATEGORY[categoryId], - reason: REASON[reasonId] - }; + describe('categoryId', () => { + it('is a number', () => { + expect(categoryId).to.be.a('number'); + }); - const code = toNumber(decomposed); + it('is the corresponding category ID', () => { + expect(categoryId).to.equal(CATEGORIES[category]); + }); + }); + describe('reason', () => { + it('is a number', () => expect(reasonId).to.be.a('number')); + + it('is the corresponding reason enum', () => { + expect(reasonId).to.equal(REASONS[reason]); + }); + }); + }); + + describe('#toNumber', () => { it('is a number', () => expect(code).to.be.a('number')); - it('is a single byte', () => expect(code).to.be.within(0, 255)); + it('is a single byte', () => expect(code).to.be.within(0x00, 0xFF)); it('places the nibbles side-by-side', () => { - expect(code).to.equal(categoryId * 16 + reasonId); + expect(code).to.equal(categoryId * 0x10 + reasonId); }); context('invalid category', () => { - const badCat = Object.assign({}, decomposed, { category: 'bad!' }); + const badCat = Object.assign({}, names, { category: 'bad!' }); it('throws', () => expect(() => toNumber(badCat)).to.throw(Error)); }); context('invalid reason', () => { - const badReason = Object.assign({}, decomposed, { reason: 'bad!' }); + const badReason = Object.assign({}, names, { reason: 'bad!' }); it('throws', () => expect(() => toNumber(badReason)).to.throw(Error)); }); }); describe('#toHexString', () => { - const decomposed = { - category: CATEGORY[randomInRange(0, 15)], - reason: REASON[randomInRange(0, 15)] - }; - it('formats correctly', () => { expect(toHexString(decomposed)).to.match(hexFormat); }); context('invalid category', () => { - const badCat = Object.assign({}, decomposed, { category: 'bad!' }); + const badCat = Object.assign({}, names, { category: 'bad!' }); it('throws', () => expect(() => toHexString(badCat)).to.throw(Error)); }); context('invalid reason', () => { - const badReason = Object.assign({}, decomposed, { reason: 'bad!' }); + const badReason = Object.assign({}, names, { reason: 'bad!' }); it('throws', () => expect(() => toHexString(badReason)).to.throw(Error)); }); }); describe('#hexifyCode', () => { - const code = randomInRange(0, 255); - it('formats correctly', () => { expect(hexifyCode(code)).to.match(hexFormat); }); diff --git a/test/lib/fission/category.spec.js b/test/lib/fission/category.spec.js index 3e22f66..436dd6e 100644 --- a/test/lib/fission/category.spec.js +++ b/test/lib/fission/category.spec.js @@ -1,13 +1,18 @@ const { expect } = require('chai'); const { randomInRange } = require('../../helpers'); -const { CATEGORY, toHexString, toId, toNumber } = require('../../../lib/fission/category'); +const { + CATEGORIES, + CATEGORY_NAMES, + toHexString, + toNumber +} = require('../../../lib/fission/category'); const hexRegex = /0x[0-9A-F]0/; describe('category', () => { const index = randomInRange(0, 15); - const cat = CATEGORY[index]; + const cat = CATEGORY_NAMES[index]; describe('#toHexString', () => { context('with hex value 0-9', () => { @@ -49,30 +54,6 @@ describe('category', () => { }); }); - describe('#toId', () => { - it('translates the category name into its uint8 enum equivalent', () => { - expect(toId(cat)).to.equal(index); - }); - - context('not a valid category', () => { - it('throws', () => { - expect(() => toId('foo')).to.throw(Error); - }); - }); - - context('not a string', () => { - it('throws', () => { - expect(() => toId(42)).to.throw(Error); - }); - }); - - context('wrong case', () => { - it('throws', () => { - expect(() => toId('generic')).to.throw(Error); - }); - }); - }); - describe('#toNumber', () => { it('translates the category name into its numeric prefix equivalent', () => { expect(toNumber(cat)).to.equal(index * 16); diff --git a/test/lib/fission/reason.spec.js b/test/lib/fission/reason.spec.js index 34f7245..3e391a8 100644 --- a/test/lib/fission/reason.spec.js +++ b/test/lib/fission/reason.spec.js @@ -1,13 +1,19 @@ const { expect } = require('chai'); const { randomInRange } = require('../../helpers'); -const { REASON, toHexString, toId, toNumber } = require('../../../lib/fission/reason'); +const { + REASONS, + REASON_NAMES, + toHexString, + toId, + toNumber +} = require('../../../lib/fission/reason'); const hexRegex = /0x0[0-9A-F]/; describe('reason', () => { const index = randomInRange(0, 15); - const rsn = REASON[index]; + const rsn = REASON_NAMES[index]; describe('#toHexString', () => { context('with hex value 0-9', () => { @@ -49,30 +55,6 @@ describe('reason', () => { }); }); - describe('#toId', () => { - it('translates the reason name into its uint8 enum equivalent', () => { - expect(toId(rsn)).to.equal(index); - }); - - context('not a valid reason', () => { - it('throws', () => { - expect(() => toId('foo')).to.throw(Error); - }); - }); - - context('not a string', () => { - it('throws', () => { - expect(() => toId(42)).to.throw(Error); - }); - }); - - context('wrong case', () => { - it('throws', () => { - expect(() => toId('success')).to.throw(Error); - }); - }); - }); - describe('#toNumber', () => { it('translates the reason name into its uint8 enum equivalent', () => { expect(toNumber(rsn)).to.equal(index);