2019-08-25 02:39:20 -04:00
"use strict" ;
let _permanentCensorErrors = false ;
let _censorErrors = false ;
2020-03-21 12:48:22 -04:00
const LogLevels = { debug : 1 , "default" : 2 , info : 2 , warning : 3 , error : 4 , off : 5 } ;
2020-04-25 03:54:54 -04:00
let _logLevel = LogLevels [ "default" ] ;
2019-08-25 02:39:20 -04:00
import { version } from "./_version" ;
let _globalLogger = null ;
function _checkNormalize ( ) {
try {
2019-11-20 18:57:38 +09:00
const missing = [ ] ;
2019-08-25 02:39:20 -04:00
// Make sure all forms of normalization are supported
[ "NFD" , "NFC" , "NFKD" , "NFKC" ] . forEach ( ( form ) => {
try {
if ( "test" . normalize ( form ) !== "test" ) {
throw new Error ( "bad normalize" ) ;
}
;
}
catch ( error ) {
missing . push ( form ) ;
}
} ) ;
if ( missing . length ) {
throw new Error ( "missing " + missing . join ( ", " ) ) ;
}
if ( String . fromCharCode ( 0xe9 ) . normalize ( "NFD" ) !== String . fromCharCode ( 0x65 , 0x0301 ) ) {
throw new Error ( "broken implementation" ) ;
}
}
catch ( error ) {
return error . message ;
}
return null ;
}
2019-11-20 18:57:38 +09:00
const _normalizeError = _checkNormalize ( ) ;
2020-04-25 03:54:54 -04:00
export var LogLevel ;
( function ( LogLevel ) {
LogLevel [ "DEBUG" ] = "DEBUG" ;
LogLevel [ "INFO" ] = "INFO" ;
LogLevel [ "WARNING" ] = "WARNING" ;
LogLevel [ "ERROR" ] = "ERROR" ;
LogLevel [ "OFF" ] = "OFF" ;
} ) ( LogLevel || ( LogLevel = { } ) ) ;
export var ErrorCode ;
( function ( ErrorCode ) {
///////////////////
// Generic Errors
// Unknown Error
ErrorCode [ "UNKNOWN_ERROR" ] = "UNKNOWN_ERROR" ;
// Not Implemented
ErrorCode [ "NOT_IMPLEMENTED" ] = "NOT_IMPLEMENTED" ;
// Unsupported Operation
// - operation
ErrorCode [ "UNSUPPORTED_OPERATION" ] = "UNSUPPORTED_OPERATION" ;
// Network Error (i.e. Ethereum Network, such as an invalid chain ID)
ErrorCode [ "NETWORK_ERROR" ] = "NETWORK_ERROR" ;
// Some sort of bad response from the server
ErrorCode [ "SERVER_ERROR" ] = "SERVER_ERROR" ;
// Timeout
ErrorCode [ "TIMEOUT" ] = "TIMEOUT" ;
///////////////////
// Operational Errors
// Buffer Overrun
ErrorCode [ "BUFFER_OVERRUN" ] = "BUFFER_OVERRUN" ;
// Numeric Fault
// - operation: the operation being executed
// - fault: the reason this faulted
ErrorCode [ "NUMERIC_FAULT" ] = "NUMERIC_FAULT" ;
///////////////////
// Argument Errors
// Missing new operator to an object
// - name: The name of the class
ErrorCode [ "MISSING_NEW" ] = "MISSING_NEW" ;
// Invalid argument (e.g. value is incompatible with type) to a function:
// - argument: The argument name that was invalid
// - value: The value of the argument
ErrorCode [ "INVALID_ARGUMENT" ] = "INVALID_ARGUMENT" ;
// Missing argument to a function:
// - count: The number of arguments received
// - expectedCount: The number of arguments expected
ErrorCode [ "MISSING_ARGUMENT" ] = "MISSING_ARGUMENT" ;
// Too many arguments
// - count: The number of arguments received
// - expectedCount: The number of arguments expected
ErrorCode [ "UNEXPECTED_ARGUMENT" ] = "UNEXPECTED_ARGUMENT" ;
///////////////////
// Blockchain Errors
// Call exception
// - transaction: the transaction
// - address?: the contract address
// - args?: The arguments passed into the function
// - method?: The Solidity method signature
// - errorSignature?: The EIP848 error signature
// - errorArgs?: The EIP848 error parameters
// - reason: The reason (only for EIP848 "Error(string)")
ErrorCode [ "CALL_EXCEPTION" ] = "CALL_EXCEPTION" ;
// Insufficien funds (< value + gasLimit * gasPrice)
// - transaction: the transaction attempted
ErrorCode [ "INSUFFICIENT_FUNDS" ] = "INSUFFICIENT_FUNDS" ;
// Nonce has already been used
// - transaction: the transaction attempted
ErrorCode [ "NONCE_EXPIRED" ] = "NONCE_EXPIRED" ;
// The replacement fee for the transaction is too low
// - transaction: the transaction attempted
ErrorCode [ "REPLACEMENT_UNDERPRICED" ] = "REPLACEMENT_UNDERPRICED" ;
// The gas limit could not be estimated
// - transaction: the transaction passed to estimateGas
ErrorCode [ "UNPREDICTABLE_GAS_LIMIT" ] = "UNPREDICTABLE_GAS_LIMIT" ;
} ) ( ErrorCode || ( ErrorCode = { } ) ) ;
;
2019-08-25 02:39:20 -04:00
export class Logger {
constructor ( version ) {
Object . defineProperty ( this , "version" , {
enumerable : true ,
value : version ,
writable : false
} ) ;
}
_log ( logLevel , args ) {
2020-03-21 12:48:22 -04:00
const level = logLevel . toLowerCase ( ) ;
if ( LogLevels [ level ] == null ) {
this . throwArgumentError ( "invalid log level name" , "logLevel" , logLevel ) ;
}
2020-04-25 03:54:54 -04:00
if ( _logLevel > LogLevels [ level ] ) {
2019-08-25 02:39:20 -04:00
return ;
}
console . log . apply ( console , args ) ;
}
debug ( ... args ) {
this . _log ( Logger . levels . DEBUG , args ) ;
}
info ( ... args ) {
this . _log ( Logger . levels . INFO , args ) ;
}
warn ( ... args ) {
this . _log ( Logger . levels . WARNING , args ) ;
}
makeError ( message , code , params ) {
2020-02-17 20:22:33 -05:00
// Errors are being censored
2019-08-25 02:39:20 -04:00
if ( _censorErrors ) {
2020-02-17 20:22:33 -05:00
return this . makeError ( "censored error" , code , { } ) ;
2019-08-25 02:39:20 -04:00
}
if ( ! code ) {
code = Logger . errors . UNKNOWN _ERROR ;
}
if ( ! params ) {
params = { } ;
}
2019-11-20 18:57:38 +09:00
const messageDetails = [ ] ;
2019-08-25 02:39:20 -04:00
Object . keys ( params ) . forEach ( ( key ) => {
try {
messageDetails . push ( key + "=" + JSON . stringify ( params [ key ] ) ) ;
}
catch ( error ) {
messageDetails . push ( key + "=" + JSON . stringify ( params [ key ] . toString ( ) ) ) ;
}
} ) ;
2020-02-04 01:06:47 -05:00
messageDetails . push ( ` code= ${ code } ` ) ;
messageDetails . push ( ` version= ${ this . version } ` ) ;
2019-11-20 18:57:38 +09:00
const reason = message ;
2019-08-25 02:39:20 -04:00
if ( messageDetails . length ) {
message += " (" + messageDetails . join ( ", " ) + ")" ;
}
// @TODO: Any??
2019-11-20 18:57:38 +09:00
const error = new Error ( message ) ;
2019-08-25 02:39:20 -04:00
error . reason = reason ;
error . code = code ;
Object . keys ( params ) . forEach ( function ( key ) {
error [ key ] = params [ key ] ;
} ) ;
return error ;
}
throwError ( message , code , params ) {
throw this . makeError ( message , code , params ) ;
}
throwArgumentError ( message , name , value ) {
return this . throwError ( message , Logger . errors . INVALID _ARGUMENT , {
argument : name ,
value : value
} ) ;
}
checkNormalize ( message ) {
if ( message == null ) {
message = "platform missing String.prototype.normalize" ;
}
if ( _normalizeError ) {
this . throwError ( "platform missing String.prototype.normalize" , Logger . errors . UNSUPPORTED _OPERATION , {
operation : "String.prototype.normalize" , form : _normalizeError
} ) ;
}
}
checkSafeUint53 ( value , message ) {
if ( typeof ( value ) !== "number" ) {
return ;
}
if ( message == null ) {
message = "value not safe" ;
}
if ( value < 0 || value >= 0x1fffffffffffff ) {
this . throwError ( message , Logger . errors . NUMERIC _FAULT , {
operation : "checkSafeInteger" ,
fault : "out-of-safe-range" ,
value : value
} ) ;
}
if ( value % 1 ) {
this . throwError ( message , Logger . errors . NUMERIC _FAULT , {
operation : "checkSafeInteger" ,
fault : "non-integer" ,
value : value
} ) ;
}
}
checkArgumentCount ( count , expectedCount , message ) {
if ( message ) {
message = ": " + message ;
}
else {
message = "" ;
}
if ( count < expectedCount ) {
this . throwError ( "missing argument" + message , Logger . errors . MISSING _ARGUMENT , {
count : count ,
expectedCount : expectedCount
} ) ;
}
if ( count > expectedCount ) {
this . throwError ( "too many arguments" + message , Logger . errors . UNEXPECTED _ARGUMENT , {
count : count ,
expectedCount : expectedCount
} ) ;
}
}
checkNew ( target , kind ) {
if ( target === Object || target == null ) {
this . throwError ( "missing new" , Logger . errors . MISSING _NEW , { name : kind . name } ) ;
}
}
checkAbstract ( target , kind ) {
if ( target === kind ) {
this . throwError ( "cannot instantiate abstract class " + JSON . stringify ( kind . name ) + " directly; use a sub-class" , Logger . errors . UNSUPPORTED _OPERATION , { name : target . name , operation : "new" } ) ;
}
else if ( target === Object || target == null ) {
this . throwError ( "missing new" , Logger . errors . MISSING _NEW , { name : kind . name } ) ;
}
}
static globalLogger ( ) {
if ( ! _globalLogger ) {
_globalLogger = new Logger ( version ) ;
}
return _globalLogger ;
}
static setCensorship ( censorship , permanent ) {
2020-02-17 20:22:33 -05:00
if ( ! censorship && permanent ) {
this . globalLogger ( ) . throwError ( "cannot permanently disable censorship" , Logger . errors . UNSUPPORTED _OPERATION , {
operation : "setCensorship"
} ) ;
}
2019-08-25 02:39:20 -04:00
if ( _permanentCensorErrors ) {
if ( ! censorship ) {
return ;
}
this . globalLogger ( ) . throwError ( "error censorship permanent" , Logger . errors . UNSUPPORTED _OPERATION , {
operation : "setCensorship"
} ) ;
}
_censorErrors = ! ! censorship ;
_permanentCensorErrors = ! ! permanent ;
}
2020-02-26 10:06:48 +00:00
static setLogLevel ( logLevel ) {
const level = LogLevels [ logLevel ] ;
if ( level == null ) {
Logger . globalLogger ( ) . warn ( "invalid log level - " + logLevel ) ;
return ;
}
2020-04-25 03:54:54 -04:00
_logLevel = level ;
2020-02-26 10:06:48 +00:00
}
2019-08-25 02:39:20 -04:00
}
2020-04-25 03:54:54 -04:00
Logger . errors = ErrorCode ;
Logger . levels = LogLevel ;