Skip to content

Commit 35c4dc7

Browse files
committed
refactor: Contract validation
1 parent 1edd0bd commit 35c4dc7

File tree

8 files changed

+100
-70
lines changed

8 files changed

+100
-70
lines changed

src/commands/init.js

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ const { fixParameters } = require('../command-helpers/gluegun')
1616
const { chooseNodeUrl } = require('../command-helpers/node')
1717
const { generateScaffold, writeScaffold } = require('../command-helpers/scaffold')
1818
const { abiEvents } = require('../scaffold/schema')
19+
const { validateContract } = require('../validation')
1920
const Protocol = require('../protocols')
2021

2122
const protocolChoices = Array.from(Protocol.availableProtocols().keys())
@@ -179,14 +180,12 @@ const processInitForm = async (
179180
return true
180181
}
181182

182-
const contract = new ProtocolContract(value)
183+
// Validate whether the contract is valid
184+
const { valid, error } = validateContract(value, ProtocolContract)
183185

184-
// Validate whether the address is valid
185-
if (!contract.validate()) {
186-
return `Contract ${ProtocolContract.identifierName()} is invalid: ${value}\n${ProtocolContract.errorMessage()}`
187-
}
188-
189-
return true
186+
return valid
187+
? true
188+
: error
190189
},
191190
result: async value => {
192191
if (fromExample !== undefined) {

src/protocols/ethereum/contract.js

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,20 @@ module.exports = class EthereumContract {
33
return 'address'
44
}
55

6-
static pattern() {
7-
return /^(0x)?[0-9a-fA-F]{40}$/
8-
}
9-
10-
static errorMessage() {
11-
return "Must be 40 hexadecimal characters, with an optional '0x' prefix."
12-
}
13-
146
constructor(address) {
157
this.address = address
168
}
179

1810
validate() {
19-
return EthereumContract.pattern().test(this.address)
11+
const pattern = /^(0x)?[0-9a-fA-F]{40}$/
12+
13+
const errorMessage = "Must be 40 hexadecimal characters, with an optional '0x' prefix."
14+
15+
const valid = pattern.test(this.address)
16+
17+
return {
18+
valid,
19+
error: valid ? null : errorMessage,
20+
}
2021
}
2122
}

src/protocols/ethereum/subgraph.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
const immutable = require('immutable')
22
const ABI = require('./abi')
33
const DataSourcesExtractor = require('../../command-helpers/data-sources')
4-
const { validateContractValues } = require('../../validation')
54

65
module.exports = class EthereumSubgraph {
76
constructor(options = {}) {

src/protocols/near/contract.js

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,13 @@
11
const MINIMUM_ACCOUNT_ID_LENGTH = 2
22
const MAXIMUM_ACCOUNT_ID_LENGTH = 64
33

4+
const RULES_URL = 'https://docs.near.org/docs/concepts/account#account-id-rules'
5+
46
module.exports = class NearContract {
57
static identifierName() {
68
return 'account'
79
}
810

9-
static pattern() {
10-
return /^(([a-z\d]+[\-_])*[a-z\d]+\.)*([a-z\d]+[\-_])*[a-z\d]+$/
11-
}
12-
13-
static errorMessage() {
14-
return `Must be between '${MINIMUM_ACCOUNT_ID_LENGTH}' and '${MAXIMUM_ACCOUNT_ID_LENGTH}' characters
15-
An Account ID consists of Account ID parts separated by '.' (dots)
16-
Each Account ID part consists of lowercase alphanumeric symbols separated by either a '_' (underscore) or '-' (dash)
17-
For further information look for: https://docs.near.org/docs/concepts/account#account-id-rules`
18-
}
19-
2011
constructor(account) {
2112
this.account = account
2213
}
@@ -26,9 +17,30 @@ For further information look for: https://docs.near.org/docs/concepts/account#ac
2617
this.account.length <= MAXIMUM_ACCOUNT_ID_LENGTH
2718
}
2819

20+
_validateFormat() {
21+
const pattern = /^(([a-z\d]+[\-_])*[a-z\d]+\.)*([a-z\d]+[\-_])*[a-z\d]+$/
22+
23+
return pattern.test(this.account)
24+
}
25+
2926
validate() {
30-
// Reference: https://docs.near.org/docs/concepts/account#account-id-rules
31-
return this._validateLength(this.account) &&
32-
NearContract.pattern().test(this.account)
27+
if (!this._validateLength(this.account)) {
28+
return {
29+
valid: false,
30+
error: `Account must be between '${MINIMUM_ACCOUNT_ID_LENGTH}' and '${MAXIMUM_ACCOUNT_ID_LENGTH}' characters, see ${RULES_URL}`,
31+
}
32+
}
33+
34+
if (!this._validateFormat()) {
35+
return {
36+
valid: false,
37+
error: `Account must conform to the rules on ${RULES_URL}`,
38+
}
39+
}
40+
41+
return {
42+
valid: true,
43+
error: null,
44+
}
3345
}
3446
}

src/protocols/near/subgraph.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
const immutable = require('immutable')
2-
const { validateContractValues } = require('../../validation')
32

43
module.exports = class NearSubgraph {
54
constructor(options = {}) {

src/validation/contract.js

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
const immutable = require('immutable')
2+
3+
const validateContract = (value, ProtocolContract) => {
4+
const contract = new ProtocolContract(value)
5+
6+
const { valid, error } = contract.validate()
7+
8+
if (!valid) {
9+
return {
10+
valid,
11+
error: `Contract ${ProtocolContract.identifierName()} is invalid: ${value}\n${error}`,
12+
}
13+
}
14+
15+
return { valid, error }
16+
}
17+
18+
const validateContractValues = (manifest, protocol) => {
19+
const ProtocolContract = protocol.getContract()
20+
21+
const fieldName = ProtocolContract.identifierName()
22+
23+
return manifest
24+
.get('dataSources')
25+
.filter(dataSource => protocol.isValidKindName(dataSource.get('kind')))
26+
.reduce((errors, dataSource, dataSourceIndex) => {
27+
let path = ['dataSources', dataSourceIndex, 'source', fieldName]
28+
29+
// No need to validate if the source has no contract field
30+
if (!dataSource.get('source').has(fieldName)) {
31+
return errors
32+
}
33+
34+
let contractValue = dataSource.getIn(['source', fieldName])
35+
36+
37+
const { valid, error } = validateContract(contractValue, ProtocolContract)
38+
39+
// Validate whether the contract is valid for the protocol
40+
if (valid) {
41+
return errors
42+
} else {
43+
return errors.push(
44+
immutable.fromJS({
45+
path,
46+
message: error,
47+
}),
48+
)
49+
}
50+
}, immutable.List())
51+
}
52+
53+
module.exports = {
54+
validateContract,
55+
validateContractValues,
56+
}

src/validation/index.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
module.exports = {
22
validateSchema: require('./schema').validateSchema,
33
validateManifest: require('./manifest').validateManifest,
4-
validateContractValues: require('./manifest').validateContractValues,
4+
validateContractValues: require('./contract').validateContractValues,
5+
validateContract: require('./contract').validateContract,
56
}

src/validation/manifest.js

Lines changed: 0 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -282,43 +282,6 @@ const validateManifest = (value, type, schema, protocol, { resolveFile }) => {
282282
return validateDataSourceNetworks(value, protocol)
283283
}
284284

285-
const validateContractValues = (manifest, protocol) => {
286-
const ProtocolContract = protocol.getContract()
287-
288-
const fieldName = ProtocolContract.identifierName()
289-
const errorMessage = ProtocolContract.errorMessage()
290-
291-
return manifest
292-
.get('dataSources')
293-
.filter(dataSource => protocol.isValidKindName(dataSource.get('kind')))
294-
.reduce((errors, dataSource, dataSourceIndex) => {
295-
let path = ['dataSources', dataSourceIndex, 'source', fieldName]
296-
297-
// No need to validate if the source has no contract field
298-
if (!dataSource.get('source').has(fieldName)) {
299-
return errors
300-
}
301-
302-
let contractValue = dataSource.getIn(['source', fieldName])
303-
304-
let contract = new ProtocolContract(contractValue)
305-
306-
// Validate whether the contract is valid for the protocol
307-
if (contract.validate()) {
308-
return errors
309-
} else {
310-
return errors.push(
311-
immutable.fromJS({
312-
path,
313-
message: `\
314-
Contract ${fieldName} is invalid: ${contractValue}\n${errorMessage}`,
315-
}),
316-
)
317-
}
318-
}, immutable.List())
319-
}
320-
321285
module.exports = {
322286
validateManifest,
323-
validateContractValues,
324287
}

0 commit comments

Comments
 (0)