@certik/skynet 0.8.6 → 0.8.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +13 -4
- package/cli.js +14 -12
- package/const.js +10 -3
- package/env.js +6 -0
- package/indexer.js +6 -1
- package/package.json +1 -1
- package/scan.js +21 -14
- package/slack.js +25 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,12 +1,21 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
##0.8.
|
|
3
|
+
## 0.8.10
|
|
4
|
+
|
|
5
|
+
- Improved `postMessage` in `slack` library to support private channels
|
|
6
|
+
|
|
7
|
+
## 0.8.7
|
|
8
|
+
|
|
9
|
+
- Changed polygon node endpoint
|
|
10
|
+
|
|
11
|
+
## 0.8.6
|
|
4
12
|
|
|
5
13
|
- Fixed a const.js error
|
|
14
|
+
- Support more options in snowflake.js
|
|
6
15
|
|
|
7
|
-
##0.8.5
|
|
16
|
+
## 0.8.5
|
|
8
17
|
|
|
9
|
-
-
|
|
18
|
+
- Improved cross-OS compatibility of `detectDirectory` function
|
|
10
19
|
|
|
11
20
|
## 0.8.4
|
|
12
21
|
|
|
@@ -34,7 +43,7 @@
|
|
|
34
43
|
|
|
35
44
|
## 0.7.18
|
|
36
45
|
|
|
37
|
-
- Added the configurability for getTokenPriceAt function in `token` library
|
|
46
|
+
- Added the configurability for getTokenPriceAt function in `token` library
|
|
38
47
|
|
|
39
48
|
## 0.7.17
|
|
40
49
|
|
package/cli.js
CHANGED
|
@@ -16,22 +16,24 @@ function detectWorkingDirectory() {
|
|
|
16
16
|
const wd = detectDirectory(process.argv[1], "package.json");
|
|
17
17
|
const skynetd = detectDirectory(process.argv[1], "SkynetAPIDefinitions.yml");
|
|
18
18
|
|
|
19
|
-
return wd.slice(skynetd.length + path.sep.length);
|
|
19
|
+
return wd.slice(skynetd.length + path.sep.length).replace(path.sep, "/");
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
function detectDirectory(fullBinPath, sentinel = "package.json") {
|
|
23
|
-
|
|
23
|
+
let parentFolder = path.dirname(fullBinPath);
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
if (
|
|
33
|
-
|
|
25
|
+
while (parentFolder) {
|
|
26
|
+
// check if parentFolder length is greater than 0
|
|
27
|
+
const sentinelPath = path.join(parentFolder, sentinel);
|
|
28
|
+
if (fs.existsSync(sentinelPath)) {
|
|
29
|
+
return parentFolder;
|
|
30
|
+
}
|
|
31
|
+
const newParentFolder = path.dirname(parentFolder);
|
|
32
|
+
if (newParentFolder === parentFolder) {
|
|
33
|
+
// we have reached the root folder
|
|
34
|
+
break;
|
|
34
35
|
}
|
|
36
|
+
parentFolder = newParentFolder;
|
|
35
37
|
}
|
|
36
38
|
|
|
37
39
|
throw new Error("Cannot detect current working directory");
|
|
@@ -40,7 +42,7 @@ function detectDirectory(fullBinPath, sentinel = "package.json") {
|
|
|
40
42
|
function detectBin() {
|
|
41
43
|
const wd = detectDirectory(process.argv[1], "package.json");
|
|
42
44
|
|
|
43
|
-
return process.argv[1].slice(wd.length + path.sep.length);
|
|
45
|
+
return process.argv[1].slice(wd.length + path.sep.length).replace(path.sep, "/");
|
|
44
46
|
}
|
|
45
47
|
|
|
46
48
|
module.exports = {
|
package/const.js
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
const {
|
|
1
|
+
const {
|
|
2
|
+
getEtherScanApiKey,
|
|
3
|
+
getBscScanApiKey,
|
|
4
|
+
getPolygonScanApiKey,
|
|
5
|
+
getGetBlockApiKey,
|
|
6
|
+
getAlchemyApiKey,
|
|
7
|
+
} = require("./env");
|
|
2
8
|
|
|
3
9
|
const SKYNET_API_PREFIX = "https://api.certik-skynet.com";
|
|
4
10
|
|
|
@@ -42,8 +48,9 @@ const PROTOCOLS = {
|
|
|
42
48
|
nativeTokenAddress: "polygon:0x0000000000000000000000000000000000000000",
|
|
43
49
|
nativeTokenLogo: `https://token-logo.certik-assets.com/polygon:0x0000000000000000000000000000000000000000.png`,
|
|
44
50
|
nativeTokenCoinGeckoId: "matic-network",
|
|
45
|
-
endpoint: `https://
|
|
46
|
-
|
|
51
|
+
endpoint: `https://polygon-mainnet.g.alchemy.com/v2/${getAlchemyApiKey("POLYGON")}`,
|
|
52
|
+
backupEndpoint: `https://matic.getblock.io/mainnet/?api_key=${getGetBlockApiKey()}`,
|
|
53
|
+
archiveEndpoint: `https://polygon-mainnet.g.alchemy.com/v2/${getAlchemyApiKey("POLYGON")}`,
|
|
47
54
|
tokenStandard: "ERC20",
|
|
48
55
|
scanApi: {
|
|
49
56
|
endpoint: "https://api.polygonscan.com/api",
|
package/env.js
CHANGED
|
@@ -30,6 +30,11 @@ function getGetBlockApiKey() {
|
|
|
30
30
|
return ensureAndGet("SKYNET_GETBLOCK_API_KEY");
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
+
function getAlchemyApiKey(identifier) {
|
|
34
|
+
// Alchemy API keys are different for each alchemy app
|
|
35
|
+
return ensureAndGet(`SKYNET_ALCHEMY_API_${identifier.toUpperCase()}_KEY`);
|
|
36
|
+
}
|
|
37
|
+
|
|
33
38
|
function ensureAndGet(envName, defaultValue) {
|
|
34
39
|
if (Array.isArray(envName)) {
|
|
35
40
|
for (let name of envName) {
|
|
@@ -75,4 +80,5 @@ module.exports = {
|
|
|
75
80
|
getBscScanApiKey,
|
|
76
81
|
getPolygonScanApiKey,
|
|
77
82
|
getGetBlockApiKey,
|
|
83
|
+
getAlchemyApiKey,
|
|
78
84
|
};
|
package/indexer.js
CHANGED
|
@@ -539,7 +539,12 @@ ${getSelectorDesc(selector)}
|
|
|
539
539
|
|
|
540
540
|
async function runBuild({ verbose, ...selectorFlags }) {
|
|
541
541
|
const startTime = Date.now();
|
|
542
|
-
|
|
542
|
+
|
|
543
|
+
if (Object.keys(selectorFlags).length > 0) {
|
|
544
|
+
console.log(`[INDEXER] starting build, ${toSelectorString(selectorFlags, ", ")}`);
|
|
545
|
+
} else {
|
|
546
|
+
console.log(`[INDEXER] starting build`);
|
|
547
|
+
}
|
|
543
548
|
|
|
544
549
|
const result = await exponentialRetry(
|
|
545
550
|
async () => {
|
package/package.json
CHANGED
package/scan.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
const { exponentialRetry, wait } = require("
|
|
2
|
-
const { PROTOCOLS } = require("
|
|
1
|
+
const { exponentialRetry, wait } = require("./availability");
|
|
2
|
+
const { PROTOCOLS } = require("./const");
|
|
3
3
|
const fetch = require("node-fetch");
|
|
4
4
|
|
|
5
5
|
const BATCH_SIZE = 10_000; // Max number of transactions fetched from scan api at once
|
|
6
6
|
|
|
7
|
-
function getScanApiEndpoint(protocol, addr, startBlock = 0, endBlock = null) {
|
|
7
|
+
function getScanApiEndpoint(protocol, addr, startBlock = 0, endBlock = null, offset=BATCH_SIZE) {
|
|
8
8
|
const { endpoint, key } = PROTOCOLS[protocol].scanApi;
|
|
9
|
-
let url = `${endpoint}?module=account&action=txlist&address=${addr}&apikey=${key}&sort=asc&startblock=${startBlock}&page=1&offset=${
|
|
9
|
+
let url = `${endpoint}?module=account&action=txlist&address=${addr}&apikey=${key}&sort=asc&startblock=${startBlock}&page=1&offset=${offset}`;
|
|
10
10
|
|
|
11
11
|
if (endBlock) {
|
|
12
12
|
url += `&endblock=${endBlock}`;
|
|
@@ -15,19 +15,25 @@ function getScanApiEndpoint(protocol, addr, startBlock = 0, endBlock = null) {
|
|
|
15
15
|
return url;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
async function fetchTxs(protocol, addr,
|
|
19
|
-
const url = getScanApiEndpoint(protocol, addr,
|
|
18
|
+
async function fetchTxs(protocol, addr, since, to, offset) {
|
|
19
|
+
const url = getScanApiEndpoint(protocol, addr, since, to, offset);
|
|
20
20
|
|
|
21
|
+
try {
|
|
22
|
+
const res = await fetch(url);
|
|
23
|
+
const scanJSON = await res.json();
|
|
24
|
+
return scanJSON.result;
|
|
25
|
+
} catch (err) {
|
|
26
|
+
console.log(`error fetching txs: ${err}`)
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async function fetchTxsWithRetry(protocol, addr, since, to, offset, verbose) {
|
|
21
32
|
const txs = await exponentialRetry(
|
|
22
|
-
async () =>
|
|
23
|
-
const res = await fetch(url);
|
|
24
|
-
const scanJSON = await res.json();
|
|
25
|
-
return scanJSON.result;
|
|
26
|
-
},
|
|
33
|
+
async () => fetchTxs(protocol, addr, since, to, offset),
|
|
27
34
|
{ maxRetry: 6, test: Array.isArray, verbose }
|
|
28
35
|
)
|
|
29
36
|
|
|
30
|
-
console.log(`start block=${startBlock}, total items=${txs.length}`);
|
|
31
37
|
return txs;
|
|
32
38
|
}
|
|
33
39
|
|
|
@@ -39,7 +45,8 @@ async function streamTxs(address, since, to, callback, verbose) {
|
|
|
39
45
|
const [protocol, addr] = address.split(":");
|
|
40
46
|
|
|
41
47
|
while (hasMorePage) {
|
|
42
|
-
const txs = await fetchTxs(protocol, addr, startBlock, to, verbose);
|
|
48
|
+
const txs = await fetchTxs(protocol, addr, startBlock, to, BATCH_SIZE, verbose);
|
|
49
|
+
console.log(`start block=${since}, total items=${txs.length}`);
|
|
43
50
|
|
|
44
51
|
// This will only ever happen if the total number of txs is a multiple of our batch size
|
|
45
52
|
if (txs.length === 0) {
|
|
@@ -65,4 +72,4 @@ async function streamTxs(address, since, to, callback, verbose) {
|
|
|
65
72
|
}
|
|
66
73
|
}
|
|
67
74
|
|
|
68
|
-
module.exports = { streamTxs };
|
|
75
|
+
module.exports = { streamTxs, fetchTxs, fetchTxsWithRetry };
|
package/slack.js
CHANGED
|
@@ -19,12 +19,26 @@ function getClient() {
|
|
|
19
19
|
async function findConversation(client, name) {
|
|
20
20
|
const { conversations } = client;
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
let channels = [];
|
|
23
|
+
|
|
23
24
|
let result = await conversations.list({
|
|
25
|
+
types: "public_channel,private_channel",
|
|
24
26
|
limit: 1000,
|
|
25
27
|
});
|
|
26
28
|
|
|
27
|
-
|
|
29
|
+
channels = channels.concat(result.channels);
|
|
30
|
+
|
|
31
|
+
while (result.response_metadata.next_cursor) {
|
|
32
|
+
result = await conversations.list({
|
|
33
|
+
types: "public_channel,private_channel",
|
|
34
|
+
cursor: result.response_metadata.next_cursor,
|
|
35
|
+
limit: 1000,
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
channels = channels.concat(result.channels);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
for (const channel of channels) {
|
|
28
42
|
if (channel.name === name) {
|
|
29
43
|
const conversationId = channel.id;
|
|
30
44
|
|
|
@@ -41,6 +55,12 @@ async function postMessage(channel, message, verbose) {
|
|
|
41
55
|
|
|
42
56
|
const conversationId = await findConversation(client, channel);
|
|
43
57
|
|
|
58
|
+
if (!conversationId) {
|
|
59
|
+
throw new Error(
|
|
60
|
+
`cannot find slack public/private channel: ${channel}, you may have to invite the @CertiK Skynet bot to the channel`
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
44
64
|
let post = {};
|
|
45
65
|
|
|
46
66
|
if (typeof message === "string") {
|
|
@@ -58,9 +78,10 @@ async function postMessage(channel, message, verbose) {
|
|
|
58
78
|
...post,
|
|
59
79
|
});
|
|
60
80
|
} catch (error) {
|
|
61
|
-
// no blocking
|
|
62
81
|
console.error("failed to post slack message", error);
|
|
82
|
+
|
|
83
|
+
throw error;
|
|
63
84
|
}
|
|
64
85
|
}
|
|
65
86
|
|
|
66
|
-
module.exports = { postMessage };
|
|
87
|
+
module.exports = { getClient, findConversation, postMessage };
|