@certik/skynet 0.11.3 → 0.12.0

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 CHANGED
@@ -1,5 +1,18 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.12.0
4
+
5
+ - BREAKING: removed token module (@certik/skynet/token)
6
+ - BREAKING: removed block module (@certik/skynet/block)
7
+ - BREAKING: removed transaction module (@certik/skynet/transaction)
8
+ - BREAKING: removed primitive module (@certik/skynet/primitive)
9
+ - BREAKING: removed price module (@certik/skynet/price)
10
+ - BREAKING: removed distributed-lock module (@certik/skynet/distributed-lock)
11
+
12
+ ## 0.11.4
13
+
14
+ - support api key in query string
15
+
3
16
  ## 0.11.3
4
17
 
5
18
  - Fixed: get aws credential for production
package/api.js CHANGED
@@ -42,7 +42,7 @@ async function logEndMiddleware(req, res, next) {
42
42
  const apiKeyMiddleware = (key) => {
43
43
  async function requireAPIKey(req, res, next) {
44
44
  try {
45
- const apiKey = req.get("x-api-key");
45
+ const apiKey = req.get("x-api-key") || req.query["api-key"]; // api key present either in header or query string
46
46
 
47
47
  if (!apiKey) {
48
48
  inline.log("request without api key");
package/bun.lockb CHANGED
Binary file
package/kafka.js CHANGED
@@ -1,10 +1,9 @@
1
1
  import meow from "meow";
2
2
  import { Kafka, logLevel } from "kafkajs";
3
3
  import { getEnvironment, getEnvOrThrow } from "./env.js";
4
- import { getJobName, getSelectorFlags, getSelectorDesc, toSelectorString } from "./selector.js";
4
+ import { getSelectorFlags, getSelectorDesc, toSelectorString } from "./selector.js";
5
5
  import { createRecord, getRecordByKey, deleteRecordsByHashKey } from "./dynamodb.js";
6
6
  import { wait, exponentialRetry } from "./availability.js";
7
- import { useLock } from "./distributed-lock.js";
8
7
  import { getBinaryName } from "./cli.js";
9
8
  import { inline } from "./log.js";
10
9
 
@@ -219,8 +218,6 @@ ${getSelectorDesc(selector)}
219
218
  process.exit(0);
220
219
  }
221
220
 
222
- await useLock({ name: getJobName(name, selectorFlags), ttl: 50, verbose });
223
-
224
221
  if (!from) {
225
222
  const prevId = await getProducerLatestId(name, selectorFlags);
226
223
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@certik/skynet",
3
- "version": "0.11.3",
3
+ "version": "0.12.0",
4
4
  "description": "Skynet Shared JS library",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -15,13 +15,13 @@
15
15
  "node": ">= 18"
16
16
  },
17
17
  "dependencies": {
18
- "@aws-sdk/client-dynamodb": "^3.409.0",
19
- "@aws-sdk/client-s3": "^3.409.0",
20
- "@aws-sdk/client-sqs": "^3.409.0",
21
- "@aws-sdk/lib-dynamodb": "^3.409.0",
22
- "@opensearch-project/opensearch": "^2.3.1",
23
- "@slack/web-api": "^6.9.0",
24
- "ably": "^1.2.44",
18
+ "@aws-sdk/client-dynamodb": "^3.449.0",
19
+ "@aws-sdk/client-s3": "^3.449.0",
20
+ "@aws-sdk/client-sqs": "^3.449.0",
21
+ "@aws-sdk/lib-dynamodb": "^3.449.0",
22
+ "@opensearch-project/opensearch": "^2.4.0",
23
+ "@slack/web-api": "^6.9.1",
24
+ "ably": "^1.2.47",
25
25
  "bottleneck": "^2.19.5",
26
26
  "chalk": "^5.3.0",
27
27
  "execa": "^8.0.1",
@@ -29,8 +29,8 @@
29
29
  "kafkajs": "^2.2.4",
30
30
  "md5": "^2.3.0",
31
31
  "meow": "^12.1.1",
32
- "snowflake-sdk": "^1.8.0",
33
- "web3": "^4.1.1",
32
+ "snowflake-sdk": "^1.9.0",
33
+ "web3": "^4.2.2",
34
34
  "which": "^4.0.0"
35
35
  },
36
36
  "devDependencies": {
package/block.d.ts DELETED
@@ -1,49 +0,0 @@
1
- // See https://www.quicknode.com/docs/ethereum/eth_getBlockByNumber for a complete reference.
2
-
3
- type Transaction = {
4
- blockHash: string;
5
- blockNumber: string;
6
- hash: string;
7
- to: string;
8
- from: string;
9
- transactionIndex: string;
10
- value: string | undefined;
11
- nonce: string;
12
- gas: string;
13
- gasPrice: string;
14
- input: string;
15
- type: string;
16
- chainId: string | undefined;
17
- v: string;
18
- r: string;
19
- s: string;
20
- }
21
-
22
- type BlockInfo = {
23
- number: string;
24
- timestamp: string;
25
- difficulty: string;
26
- extraData: string;
27
- gasLimit: string;
28
- gasUsed: string;
29
- hash: string;
30
- logsBloom: string;
31
- miner: string;
32
- mixHash: string;
33
- nonce: string;
34
- parentHash: string;
35
- receiptsRoot: string;
36
- sha3Uncles: string;
37
- size: string;
38
- stateRoot: string;
39
- totalDifficulty: string;
40
- transactions: Transaction[];
41
- transactionsRoot: string;
42
- uncles: string[];
43
- }
44
-
45
- export function getLatestBlockHeight(protocol: string): Promise<number>;
46
- export function getBlock(protocol: string, height: number): Promise<BlockInfo>;
47
- export function getBlockS3Path(protocol: string, height: number): string;
48
- export function getLatestS3BlockHeight(protocol: string): Promise<number>;
49
- export function getBlockFromS3(protocol: string, height: number): Promise<BlockInfo>;
package/block.js DELETED
@@ -1,82 +0,0 @@
1
- import { Web3 } from "web3";
2
- import { getEnvironment } from "./env.js";
3
- import { PROTOCOLS } from "./const.js";
4
- import { readFile } from "./s3.js";
5
- import { getRecordByKey } from "./dynamodb.js";
6
-
7
- const S3_BUCKET_NAME =
8
- getEnvironment() === "prd" ? "certik-skynet" : "certik-skynet-dev";
9
- const INDEXER_STATE_TABLE = `skynet-${getEnvironment()}-indexer-state`;
10
-
11
- function leftPad3(num) {
12
- if (num === 0) {
13
- return "000";
14
- } else if (num < 10) {
15
- return "00" + String(num);
16
- } else if (num < 100) {
17
- return "0" + String(num);
18
- } else {
19
- return String(num);
20
- }
21
- }
22
-
23
- function getBlockS3Path(protocol, height) {
24
- return `chaindata/${protocol}/${Math.floor(height / 1_000_000)}/${leftPad3(
25
- Math.floor(height / 1_000) % 1000
26
- )}/${leftPad3(height % 1000)}.json`;
27
- }
28
-
29
- // We use this function instead of web3 because the gas limits on bsc exceed
30
- // the size supported by javascript numbers, and web3 does not support this
31
- async function getBlock(protocol, height) {
32
- const body = {
33
- jsonrpc: "2.0",
34
- method: "eth_getBlockByNumber",
35
- params: [`0x${height.toString(16)}`, true],
36
- id: 1
37
- };
38
- const response = await fetch(PROTOCOLS[protocol].endpoint, {
39
- method: "POST",
40
- headers: {
41
- "Content-Type": "application/json"
42
- },
43
- body: JSON.stringify(body)
44
- });
45
-
46
- const { result: block } = await response.json();
47
-
48
- return block;
49
- }
50
-
51
- async function getLatestBlockHeight(protocol) {
52
- const web3 = new Web3(PROTOCOLS[protocol].endpoint);
53
- const isSyncing = await web3.eth.isSyncing();
54
-
55
- if (isSyncing) {
56
- return isSyncing.currentBlock;
57
- } else {
58
- const latestBlock = await web3.eth.getBlock("latest");
59
-
60
- return latestBlock.number;
61
- }
62
- }
63
-
64
- async function getLatestS3BlockHeight(protocol) {
65
- const name = `AMLBlockIndexerSince(protocol=${protocol})`;
66
- const { value: height } = await getRecordByKey(INDEXER_STATE_TABLE, { name });
67
- return height;
68
- }
69
-
70
- async function getBlockFromS3(protocol, height) {
71
- const body = await readFile(S3_BUCKET_NAME, getBlockS3Path(protocol, height));
72
-
73
- return JSON.parse(body);
74
- }
75
-
76
- export {
77
- getLatestBlockHeight,
78
- getBlock,
79
- getBlockS3Path,
80
- getLatestS3BlockHeight,
81
- getBlockFromS3
82
- };
@@ -1 +0,0 @@
1
- export function useLock(useLockParams: { name: string, ttl: string, verbose: boolean }): Promise<string | null>
@@ -1,109 +0,0 @@
1
- async function acquireLock(name, ttl) {
2
- try {
3
- const res = await fetch("http://localhost:8500/v1/session/create", {
4
- method: "PUT",
5
- body: JSON.stringify({
6
- Name: name,
7
- TTL: `${ttl}s`,
8
- Behavior: "delete",
9
- }),
10
- });
11
-
12
- if (res.ok) {
13
- const { ID: id } = await res.json();
14
-
15
- return id;
16
- } else {
17
- console.log(res, await res.text());
18
-
19
- return null;
20
- }
21
- } catch (fetchErr) {
22
- // console.log("error fetching", fetchErr);
23
-
24
- return null;
25
- }
26
- }
27
-
28
- async function renewLock(uid) {
29
- try {
30
- const res = await fetch(`http://localhost:8500/v1/session/renew/${uid}`, {
31
- method: "PUT",
32
- });
33
-
34
- if (res.ok) {
35
- return uid;
36
- } else {
37
- console.log(res, await res.text());
38
-
39
- return null;
40
- }
41
- } catch (fetchErr) {
42
- // console.log("error fetching", fetchErr);
43
-
44
- return null;
45
- }
46
- }
47
-
48
- async function hasLock(name, uid = null) {
49
- try {
50
- const res = await fetch(`http://localhost:8500/v1/session/list`);
51
-
52
- if (res.ok) {
53
- const sessions = await res.json();
54
-
55
- const sessionsWithTheSameName = sessions.filter((s) => s.Name === name);
56
-
57
- if (!uid) {
58
- return sessionsWithTheSameName.length === 0;
59
- }
60
-
61
- if (sessionsWithTheSameName.length !== 1) {
62
- return false;
63
- }
64
-
65
- // only one should have the same uid
66
- return sessionsWithTheSameName[0].ID === uid;
67
- } else {
68
- console.log(await res.text());
69
-
70
- return true;
71
- }
72
- } catch (fetchErr) {
73
- // console.log("error fetching", fetchErr);
74
-
75
- return true;
76
- }
77
- }
78
-
79
- export async function useLock({ name, ttl, verbose }) {
80
- const lockWarningMessage = `only one process with the same lock name ${name} should be running, terminate current process`;
81
-
82
- const lockAvailable = await hasLock(name);
83
-
84
- if (!lockAvailable) {
85
- console.log(lockWarningMessage);
86
- process.exit(0);
87
- }
88
-
89
- let uid = await acquireLock(name, ttl);
90
-
91
- setInterval(async () => {
92
- if (!(await hasLock(name, uid))) {
93
- console.log(lockWarningMessage);
94
- process.exit(0);
95
- }
96
-
97
- if (uid) {
98
- if (verbose) {
99
- console.log("renewing", name, uid);
100
- }
101
-
102
- uid = await renewLock(uid);
103
- } else {
104
- uid = await acquireLock(name, ttl);
105
- }
106
- }, (ttl * 1000) / 2);
107
-
108
- return uid;
109
- }
package/price.d.ts DELETED
@@ -1,8 +0,0 @@
1
- type PricePreviousRecord = {
2
- address: string;
3
- price: number;
4
- timestamp: number;
5
- }
6
-
7
- export function getPriceClosestTo(tableName: string, address: string, timestamp: number): Promise<number>;
8
- export function getPricePreviousRecord(tableName: string, address: string, timestamp: number): Promise<PricePreviousRecord | null>;
package/price.js DELETED
@@ -1,46 +0,0 @@
1
- import { QueryCommand } from "@aws-sdk/lib-dynamodb";
2
- import { getDocClient } from "./dynamodb.js";
3
-
4
- async function queryPrice(tableName, address, timestamp, op = "<") {
5
- const docClient = getDocClient();
6
-
7
- return await docClient.send(
8
- new QueryCommand({
9
- TableName: tableName,
10
- KeyConditionExpression: `#address = :address and #timestamp ${op} :timestamp`,
11
- ExpressionAttributeNames: {
12
- "#timestamp": "timestamp",
13
- "#address": "address",
14
- },
15
- ExpressionAttributeValues: {
16
- ":timestamp": timestamp,
17
- ":address": address,
18
- },
19
- Limit: 1,
20
- ScanIndexForward: false,
21
- }),
22
- );
23
- }
24
-
25
- async function getPricePreviousRecord(tableName, address, timestamp) {
26
- const query = await queryPrice(tableName, address, timestamp, "<");
27
-
28
- if (query.Count === 0) {
29
- return null;
30
- } else {
31
- return query.Items[0];
32
- }
33
- }
34
-
35
- async function getPriceClosestTo(tableName, address, timestamp) {
36
- const query = await queryPrice(tableName, address, timestamp, "<=");
37
-
38
- if (query.Count === 0) {
39
- return 0;
40
- } else {
41
- const { price } = query.Items[0];
42
- return price;
43
- }
44
- }
45
-
46
- export { getPriceClosestTo, getPricePreviousRecord };
package/primitive.d.ts DELETED
@@ -1,29 +0,0 @@
1
- import { DynamoDB } from "aws-sdk";
2
-
3
- type Issue = {
4
- code: string;
5
- link: string;
6
- reduction: number;
7
- title: string;
8
- }
9
-
10
- export function getOverrides(
11
- docClient: DynamoDB.DocumentClient,
12
- projectId: string,
13
- address: string,
14
- log: (...data: any[]) => void,
15
- primitive: string
16
- ): Promise<string[] | null>;
17
-
18
- export function overrideScoreAndIssues(
19
- docClient: DynamoDB.DocumentClient,
20
- projectId: string,
21
- address: string,
22
- score: number,
23
- issues: Issue[],
24
- log: (...data: any[]) => void,
25
- primitive: string
26
- ): Promise<{
27
- score: number;
28
- issues: Issue[];
29
- }>
package/primitive.js DELETED
@@ -1,78 +0,0 @@
1
- async function getOverrides(docClient, projectId, address, log, primitive) {
2
- try {
3
- console.log("ProjectId:" + projectId + " address:" + address);
4
-
5
- const whitelist = [];
6
- const queryProjectOverrides = await docClient
7
- .get({
8
- TableName: "skynet-prd-primitive-manual-overrides",
9
- Key: {
10
- primitive: primitive,
11
- overrideId: "project/" + projectId,
12
- },
13
- })
14
- .promise();
15
- if (queryProjectOverrides.Item && queryProjectOverrides.Item.whitelist) {
16
- whitelist.push(...queryProjectOverrides.Item.whitelist);
17
- }
18
-
19
- const queryAddressOverrides = await docClient
20
- .get({
21
- TableName: "skynet-prd-primitive-manual-overrides",
22
- Key: {
23
- primitive: primitive,
24
- overrideId: "address/" + address,
25
- },
26
- })
27
- .promise();
28
-
29
- if (queryAddressOverrides.Item && queryAddressOverrides.Item.whitelist) {
30
- console.log(queryAddressOverrides.Item.whitelist);
31
- whitelist.push(...queryAddressOverrides.Item.whitelist);
32
- }
33
- if (whitelist.length === 0) {
34
- log(
35
- "ProjectId " + projectId + " ,Address " + address + " has no override"
36
- );
37
- }
38
- console.log("Whitelist:" + whitelist);
39
- return whitelist;
40
- } catch (scanFeedErr) {
41
- log("scan feed error, check dynamodb table", scanFeedErr);
42
- return null;
43
- }
44
- }
45
-
46
- async function overrideScoreAndIssues(
47
- docClient,
48
- projectId,
49
- address,
50
- score,
51
- issues,
52
- log,
53
- primitive
54
- ) {
55
- const overrides = await getOverrides(
56
- docClient,
57
- projectId,
58
- address,
59
- log,
60
- primitive
61
- );
62
-
63
- issues = issues.filter((issue) => {
64
- if (overrides.includes(issue.code)) {
65
- score += issue.reduction;
66
- return false;
67
- } else return true;
68
- });
69
- return {
70
- score,
71
- issues,
72
- };
73
- }
74
-
75
- export {
76
- getOverrides,
77
- overrideScoreAndIssues,
78
- };
package/token.d.ts DELETED
@@ -1,5 +0,0 @@
1
- import { BigNumber } from "bignumber.js";
2
-
3
- export function getTokenPriceAt(tokenAddress: string, timestamp: number, useCache: boolean | undefined): Promise<number>;
4
- export function toNativeDecimal(bigNumber: BigNumber, decimals: number): Promise<BigNumber>;
5
- export function toHumanDecimal(bigNumber: BigNumber, decimals: number): Promise<BigNumber>;
package/token.js DELETED
@@ -1,46 +0,0 @@
1
- import { getEnvironment } from "./env.js";
2
- import { getPriceClosestTo } from "./price.js";
3
- import BigNumber from "bignumber.js";
4
-
5
- const TOKEN_PRICE_TABLE_NAME = `skynet-${getEnvironment()}-token-prices`;
6
- const TOKEN_PRICE_CACHE = {};
7
-
8
- async function getTokenPriceAt(tokenAddress, timestamp, useCache = true) {
9
- // to avoid huge amount of dynamodb query
10
- // "ceil" timestamp to the closest proximate timestamp
11
- // 100_000 seconds ~= a bit more than 1 day 86_400 seconds
12
- // and use cache
13
- const proximateTimestamp = timestamp + 100_000 - (timestamp % 100_000);
14
-
15
- if (useCache && TOKEN_PRICE_CACHE[tokenAddress] && TOKEN_PRICE_CACHE[tokenAddress][proximateTimestamp]) {
16
- return TOKEN_PRICE_CACHE[tokenAddress][proximateTimestamp];
17
- }
18
-
19
- const price = await getPriceClosestTo(TOKEN_PRICE_TABLE_NAME, tokenAddress, proximateTimestamp);
20
-
21
- if (useCache) {
22
- if (!TOKEN_PRICE_CACHE[tokenAddress]) {
23
- TOKEN_PRICE_CACHE[tokenAddress] = {};
24
- }
25
-
26
- TOKEN_PRICE_CACHE[tokenAddress][proximateTimestamp] = price;
27
- }
28
-
29
- return price;
30
- }
31
-
32
- function toNativeDecimal(bigNumber, decimals) {
33
- const dividend = new BigNumber(10).exponentiatedBy(new BigNumber(decimals));
34
- return new BigNumber(bigNumber).multipliedBy(dividend);
35
- }
36
-
37
- function toHumanDecimal(bigNumber, decimals) {
38
- const dividend = new BigNumber(10).exponentiatedBy(new BigNumber(decimals));
39
- return new BigNumber(bigNumber).dividedBy(dividend);
40
- }
41
-
42
- export {
43
- getTokenPriceAt,
44
- toNativeDecimal,
45
- toHumanDecimal,
46
- };
package/transaction.d.ts DELETED
@@ -1,30 +0,0 @@
1
- type Log = {
2
- address: string,
3
- topics: string[],
4
- data: string,
5
- blockNumber: string,
6
- transactionHash: string,
7
- transactionIndex: string,
8
- blockHash: string,
9
- logIndex: string,
10
- removed: boolean
11
- }
12
-
13
- type TransactionReceipt = {
14
- blockHash: string,
15
- blockNumber: string,
16
- contractAddress: string | null,
17
- cumulativeGasUsed: string,
18
- effectiveGasPrice: string,
19
- from: string,
20
- gasUsed: string,
21
- logs: Log[],
22
- logsBloom: string,
23
- status: string,
24
- to: string,
25
- transactionHash: string,
26
- transactionIndex: string,
27
- type: string
28
- }
29
-
30
- export function getTxReceipt(protocol: string, txHash: string, verbose: boolean): Promise<TransactionReceipt | null>;
package/transaction.js DELETED
@@ -1,42 +0,0 @@
1
- import { PROTOCOLS } from "./const.js";
2
- import { exponentialRetry } from "./availability.js";
3
-
4
- async function getTxReceipt(protocol, txHash, verbose = false) {
5
- const { endpoint } = PROTOCOLS[protocol];
6
-
7
- console.log("got endpoint", protocol, endpoint);
8
-
9
- const body = {
10
- jsonrpc: "2.0",
11
- method: "eth_getTransactionReceipt",
12
- params: [txHash],
13
- id: 1
14
- };
15
-
16
- const response = await exponentialRetry(
17
- () => {
18
- return fetch(endpoint, {
19
- method: "POST",
20
- headers: { "Content-Type": "application/json" },
21
- body: JSON.stringify(body)
22
- });
23
- },
24
- {
25
- maxRetry: 6,
26
- test: r => r.ok,
27
- verbose
28
- }
29
- );
30
-
31
- if (!response.ok) {
32
- return null;
33
- }
34
-
35
- const { result } = await response.json();
36
-
37
- return result;
38
- }
39
-
40
- export {
41
- getTxReceipt
42
- };