Skip to content

Commit

Permalink
Merge pull request #470 from EdgeApp/william/no-json-schema
Browse files Browse the repository at this point in the history
Replace all JSON Schema uses with Cleaners
  • Loading branch information
peachbits authored Jan 2, 2023
2 parents 4eb9953 + df37c13 commit e73765d
Show file tree
Hide file tree
Showing 9 changed files with 100 additions and 167 deletions.
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,6 @@
"ethereumjs-util": "^5.2.0",
"ethereumjs-wallet": "https://github.com/EdgeApp/ethereumjs-wallet.git#6157e11ea10a734fbe55f4c7ea542780975b60ef",
"eztz.js": "https://github.com/EdgeApp/eztz.git#edge-fixes",
"jsonschema": "^1.1.1",
"rfc4648": "^1.5.0",
"stellar-sdk": "^0.11.0",
"tezos-uri": "^1.0.3",
Expand Down
15 changes: 0 additions & 15 deletions src/common/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import {
EdgeTransaction,
JsonObject
} from 'edge-core-js/types'
import { validate } from 'jsonschema'

function normalizeAddress(address: string): string {
return address.toLowerCase().replace('0x', '')
Expand All @@ -34,19 +33,6 @@ function shuffleArray<T>(array: T[]): T[] {

return array
}
function validateObject(object: any, schema: any): boolean {
const result = validate(object, schema)

if (result.errors.length === 0) {
return true
} else {
for (const error of result.errors) {
const errMsg = error.message
console.log('ERROR: validateObject:' + errMsg)
}
return false
}
}

export function isEmpty(map: Object): boolean {
return Object.keys(map).length !== 0
Expand Down Expand Up @@ -411,7 +397,6 @@ export function biggyRoundToNearestInt(float: string): string {

export {
normalizeAddress,
validateObject,
getDenomInfo,
asyncWaterfall,
snooze,
Expand Down
17 changes: 8 additions & 9 deletions src/eos/eosEngine.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* eslint-disable camelcase */

import { div, eq, gt, mul, toFixed } from 'biggystring'
import { asEither } from 'cleaners'
import { asEither, asMaybe } from 'cleaners'
import {
EdgeCurrencyEngine,
EdgeCurrencyEngineOptions,
Expand All @@ -28,19 +28,18 @@ import {
getDenomInfo,
getFetchCors,
getOtherParams,
pickRandom,
validateObject
pickRandom
} from '../common/utils'
import { checkAddress, EosTools } from './eosPlugin'
import {
asDfuseGetKeyAccountsResponse,
asDfuseGetTransactionsErrorResponse,
asDfuseGetTransactionsResponse,
asEosTransactionSuperNodeSchema,
asGetAccountActivationQuote,
asHyperionGetTransactionResponse,
asHyperionTransaction,
dfuseGetTransactionsQueryString,
EosTransactionSuperNodeSchema
dfuseGetTransactionsQueryString
} from './eosSchema'
import {
EosNetworkInfo,
Expand Down Expand Up @@ -228,16 +227,16 @@ export class EosEngine extends CurrencyEngine<EosTools> {
}

processIncomingTransaction(action: EosTransactionSuperNode): number {
const result = validateObject(action, EosTransactionSuperNodeSchema)
if (!result) {
const clean = asMaybe(asEosTransactionSuperNodeSchema)(action)
if (clean == null) {
this.error('Invalid supernode tx')
return 0
}

// eslint-disable-next-line @typescript-eslint/naming-convention
const { act, trx_id, block_num } = action
const { act, trx_id, block_num } = clean
// eslint-disable-next-line @typescript-eslint/naming-convention
const block_time = action['@timestamp']
const block_time = clean['@timestamp']

const { from, to, memo, symbol } = act.data
const exchangeAmount = act.data.amount.toString()
Expand Down
42 changes: 14 additions & 28 deletions src/eos/eosSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,31 +121,17 @@ query ($query: String!, $limit: Int64, $low: Int64, $high: Int64) {
}
`

// note that transfers are regular EOS transactions
export const EosTransactionSuperNodeSchema = {
type: 'object',
properties: {
act: {
type: 'object',
properties: {
data: {
type: 'object',
properties: {
from: { type: 'string' },
to: { type: 'string' },
amount: { type: 'number' },
symbol: { type: 'string' },
memo: { type: 'string' }
},
required: ['from', 'to', 'amount'],
authorization: { type: 'object' }
}
},
required: ['data']
},
trx_id: { type: 'string' },
'@timestamp': { type: 'string' },
block_num: { type: 'number' },
required: ['act', 'trx_id', '@timestamp', 'block_num']
}
}
export const asEosTransactionSuperNodeSchema = asObject({
act: asObject({
data: asObject({
from: asString,
to: asString,
amount: asNumber,
symbol: asString,
memo: asOptional(asString)
})
}),
trx_id: asString,
'@timestamp': asString,
block_num: asNumber
})
26 changes: 10 additions & 16 deletions src/ethereum/ethEngine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,12 @@ import {
normalizeAddress,
removeHexPrefix,
timeout,
toHex,
validateObject
toHex
} from '../common/utils'
import { NETWORK_FEES_POLL_MILLISECONDS, WEI_MULTIPLIER } from './ethConsts'
import { EthereumNetwork, getFeeRateUsed } from './ethNetwork'
import { EthereumTools } from './ethPlugin'
import { EIP712TypedDataSchema } from './ethSchema'
import { asEIP712TypedData } from './ethSchema'
import {
asEthereumTxOtherParams,
asWcSessionRequestParams,
Expand Down Expand Up @@ -140,11 +139,10 @@ export class EthereumEngine
// @ts-expect-error
signTypedData: (typedData: EIP712TypedDataParam) => {
// Adapted from https://github.com/ethereum/EIPs/blob/master/assets/eip-712/Example.js
const valid = validateObject(typedData, EIP712TypedDataSchema)
if (!valid) throw new Error('ErrorInvalidTypedData')
const clean = asEIP712TypedData(typedData)

const privKey = Buffer.from(this.getDisplayPrivateSeed(), 'hex')
const types = typedData.types
const { types } = clean

// Recursively finds all the dependencies of a type
// @ts-expect-error
Expand All @@ -169,9 +167,8 @@ export class EthereumEngine
return found
}

// @ts-expect-error
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
function encodeType(primaryType) {
function encodeType(primaryType: string) {
// Get dependencies primary first, then alphabetical
let deps = dependencies(primaryType)
deps = deps.filter(t => t !== primaryType)
Expand All @@ -189,15 +186,13 @@ export class EthereumEngine
return result
}

// @ts-expect-error
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
function typeHash(primaryType) {
function typeHash(primaryType: string) {
return EthereumUtil.keccak256(encodeType(primaryType))
}

// @ts-expect-error
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
function encodeData(primaryType, data) {
function encodeData(primaryType: string, data: any) {
const encTypes = []
const encValues = []

Expand Down Expand Up @@ -227,9 +222,8 @@ export class EthereumEngine
return abi.rawEncode(encTypes, encValues)
}

// @ts-expect-error
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
function structHash(primaryType, data) {
function structHash(primaryType: string, data: any) {
return EthereumUtil.keccak256(encodeData(primaryType, data))
}

Expand All @@ -238,8 +232,8 @@ export class EthereumEngine
return EthereumUtil.keccak256(
Buffer.concat([
Buffer.from('1901', 'hex'),
structHash('EIP712Domain', typedData.domain),
structHash(typedData.primaryType, typedData.message)
structHash('EIP712Domain', clean.domain),
structHash(clean.primaryType, clean.message)
])
)
}
Expand Down
28 changes: 10 additions & 18 deletions src/ethereum/ethNetwork.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,14 @@ import {
removeHexPrefix,
safeErrorMessage,
shuffleArray,
snooze,
validateObject
snooze
} from '../common/utils'
import { WEI_MULTIPLIER } from './ethConsts'
import { EthereumEngine } from './ethEngine'
import { EtherscanGetAccountNonce, EtherscanGetBlockHeight } from './ethSchema'
import {
asEtherscanGetAccountNonce,
asEtherscanGetBlockHeight
} from './ethSchema'
import {
AlethioTokenTransfer,
asBlockbookAddress,
Expand Down Expand Up @@ -1051,7 +1053,7 @@ export class EthereumNetwork {
out = await asyncWaterfall(funcs)
} else {
/*
// HACK: If a currency doesn't have an etherscan API compatible
// HACK: If a currency doesn't have an etherscan API compatible
// server we need to return an empty array
*/

Expand Down Expand Up @@ -1146,13 +1148,8 @@ export class EthereumNetwork {
const { result: jsonObj, server } = await this.multicastServers(
'eth_blockNumber'
)
const valid = validateObject(jsonObj, EtherscanGetBlockHeight)
if (valid && /0[xX][0-9a-fA-F]+/.test(jsonObj.result)) {
const blockHeight = parseInt(jsonObj.result, 16)
return { blockHeight, server }
} else {
throw new Error('Ethscan returned invalid JSON')
}
const clean = asEtherscanGetBlockHeight(jsonObj)
return { blockHeight: clean.result, server }
}

// @ts-expect-error
Expand Down Expand Up @@ -1226,13 +1223,8 @@ export class EthereumNetwork {
'eth_getTransactionCount',
address
)
const valid = validateObject(jsonObj, EtherscanGetAccountNonce)
if (valid && /0[xX][0-9a-fA-F]+/.test(jsonObj.result)) {
const newNonce = add('0', jsonObj.result)
return { newNonce, server }
} else {
throw new Error('Ethscan returned invalid JSON')
}
const clean = asEtherscanGetAccountNonce(jsonObj)
return { newNonce: clean.result, server }
}

// @ts-expect-error
Expand Down
94 changes: 45 additions & 49 deletions src/ethereum/ethSchema.ts
Original file line number Diff line number Diff line change
@@ -1,54 +1,50 @@
export const EtherscanGetBlockHeight = {
type: 'object',
properties: {
result: { type: 'string' }
},
required: ['result']
}
import { add } from 'biggystring'
import {
asArray,
asNumber,
asObject,
asString,
asUnknown,
Cleaner
} from 'cleaners'

export const EtherscanGetAccountNonce = {
type: 'object',
properties: {
result: { type: 'string' }
},
required: ['result']
const asHexNumber: Cleaner<number> = raw => {
const clean = asString(raw)
if (/0[xX][0-9a-fA-F]+/.test(clean)) return parseInt(clean, 16)
throw new TypeError('Expected a hex number')
}

export const EthGasStationSchema = {
type: 'object',
properties: {
safeLow: { type: 'number' },
average: { type: 'number' },
standard: { type: 'number' },
fastest: { type: 'number' }
},
required: ['safeLow', 'fastest']
const asHexString: Cleaner<string> = raw => {
const clean = asString(raw)
if (/0[xX][0-9a-fA-F]+/.test(clean)) return add(raw, '0')
throw new TypeError('Expected a hex number')
}

export const EIP712TypedDataSchema = {
type: 'object',
properties: {
types: {
type: 'object',
properties: {
EIP712Domain: { type: 'array' }
},
additionalProperties: {
type: 'array',
items: {
type: 'object',
properties: {
name: { type: 'string' },
type: { type: 'string' }
},
required: ['name', 'type']
}
},
required: ['EIP712Domain']
},
primaryType: { type: 'string' },
domain: { type: 'object' },
message: { type: 'object' }
},
required: ['types', 'primaryType', 'domain', 'message']
}
export const asEtherscanGetBlockHeight = asObject({
result: asHexNumber
})

export const asEtherscanGetAccountNonce = asObject({
result: asHexString
})

export const asEthGasStation = asObject({
safeLow: asNumber,
average: asNumber,
fast: asNumber,
fastest: asNumber
})

export const asEIP712TypedData = asObject({
types: asObject(
asArray(
asObject({
name: asString,
type: asString
})
)
),
primaryType: asString,
domain: asUnknown,
message: asUnknown
})
Loading

0 comments on commit e73765d

Please sign in to comment.