@strkfarm/sdk 1.0.6

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/package.json ADDED
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "@strkfarm/sdk",
3
+ "version": "1.0.6",
4
+ "description": "STRKFarm TS SDK (Meant for our internal use, but feel free to use it)",
5
+ "typings": "dist/index.d.ts",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "bin": {
9
+ "accountsecure": "./dist/cli.js"
10
+ },
11
+ "exports": {
12
+ ".": {
13
+ "import": "./dist/index.mjs",
14
+ "require": "./dist/index.js",
15
+ "browser": "./dist/index.global.js",
16
+ "types": "./dist/index.d.ts"
17
+ }
18
+ },
19
+ "files": [
20
+ "dist",
21
+ "src"
22
+ ],
23
+ "scripts": {
24
+ "test": "jest",
25
+ "build": "tsup --clean && pnpm run build:esm && npm run build:dts && npm run build:iife && npm run build-cli",
26
+ "build:esm": "tsup --clean false --format esm --platform node",
27
+ "build-cli:esm": "tsup ./src/cli.ts --clean false --format esm --platform node",
28
+ "build-cli": "tsup ./src/cli.ts --clean false && pnpm run build-cli:esm",
29
+ "build:dts": "tsup --clean false --dts-only",
30
+ "build:iife": "tsup --clean false --format iife --platform browser"
31
+ },
32
+ "keywords": [],
33
+ "author": "",
34
+ "license": "ISC",
35
+ "devDependencies": {
36
+ "@types/jest": "^29.5.12",
37
+ "@types/node-telegram-bot-api": "^0.64.7",
38
+ "jest": "^29.7.0",
39
+ "jest-environment-jsdom": "^29.7.0",
40
+ "ts-jest": "^29.1.5",
41
+ "ts-node": "^10.9.2",
42
+ "tsup": "^8.1.0",
43
+ "typedoc": "^0.26.3",
44
+ "typescript": "^5.5.3"
45
+ },
46
+ "dependencies": {
47
+ "axios": "^1.7.2",
48
+ "bignumber.js": "4.0.4",
49
+ "browser-assert": "^1.2.1",
50
+ "chalk": "^4.1.2",
51
+ "commander": "^12.1.0",
52
+ "inquirer": "^10.1.2",
53
+ "node-telegram-bot-api": "^0.66.0",
54
+ "redis": "^4.7.0",
55
+ "starknet": "^6.11.0",
56
+ "winston": "^3.13.0"
57
+ }
58
+ }
package/src/cli.ts ADDED
@@ -0,0 +1,160 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { Command } from 'commander';
4
+ import inquirer from 'inquirer';
5
+ import { Store, getDefaultStoreConfig } from './utils/store';
6
+ import chalk from 'chalk';
7
+ import { IConfig, Network } from './interfaces';
8
+ import { RpcProvider } from 'starknet';
9
+
10
+ const program = new Command();
11
+
12
+ const getConfig = (network: Network) => {
13
+ return {
14
+ provider: new RpcProvider({
15
+ nodeUrl: 'https://starknet-mainnet.public.blastapi.io',
16
+ }),
17
+ network: network,
18
+ stage: 'production',
19
+ }
20
+ }
21
+
22
+ async function createStore() {
23
+ console.log(chalk.blue.bold('Welcome to the Account Secure project for Starknet!'));
24
+ const networkAnswers = await (<any>inquirer).prompt([
25
+ {
26
+ type: 'list',
27
+ name: 'network',
28
+ message: chalk.yellow('What is the network?'),
29
+ choices: ['mainnet', 'sepolia', 'devnet'],
30
+ },
31
+ ]);
32
+ const network: Network = networkAnswers.network as Network;
33
+ const defaultStoreConfig = getDefaultStoreConfig(network);
34
+
35
+ const storeConfigAnswers = await (<any>inquirer).prompt([
36
+ {
37
+ type: 'input',
38
+ name: 'secrets_folder',
39
+ message: chalk.yellow(`What is your secrets folder? (${defaultStoreConfig.SECRET_FILE_FOLDER})`),
40
+ default: defaultStoreConfig.SECRET_FILE_FOLDER,
41
+ validate: (input: string) => true,
42
+ },
43
+ {
44
+ type: 'input',
45
+ name: 'accounts_file',
46
+ message: chalk.yellow(`What is your accounts file? (${defaultStoreConfig.ACCOUNTS_FILE_NAME})`),
47
+ default: defaultStoreConfig.ACCOUNTS_FILE_NAME,
48
+ validate: (input: string) => true,
49
+ },
50
+ {
51
+ type: 'input',
52
+ name: 'encryption_password',
53
+ message: chalk.yellow(`What is your decryption password? (To generate one, press enter)`),
54
+ default: defaultStoreConfig.PASSWORD,
55
+ validate: (input: string) => true,
56
+ }
57
+ ]);
58
+
59
+ const config = getConfig(network);
60
+
61
+ const secrets_folder = storeConfigAnswers.secrets_folder;
62
+ const accounts_file = storeConfigAnswers.accounts_file;
63
+ const encryption_password = storeConfigAnswers.encryption_password;
64
+
65
+ const store = new Store(config, {
66
+ SECRET_FILE_FOLDER: secrets_folder,
67
+ ACCOUNTS_FILE_NAME: accounts_file,
68
+ PASSWORD: storeConfigAnswers.encryption_password,
69
+ NETWORK: network,
70
+ });
71
+
72
+ if (defaultStoreConfig.PASSWORD === encryption_password) {
73
+ Store.logPassword(encryption_password);
74
+ }
75
+
76
+ return store;
77
+ }
78
+
79
+ program
80
+ .version('1.0.0')
81
+ .description('Manage accounts securely on your disk with encryption');
82
+
83
+ program
84
+ .description('Add accounts securely to your disk with encryption')
85
+ .command('add-account')
86
+ .action(async (options) => {
87
+ const store = await createStore();
88
+
89
+ const existingAccountKeys = store.listAccounts();
90
+
91
+ const accountAnswers = await (<any>inquirer).prompt([
92
+ {
93
+ type: 'input',
94
+ name: 'account_key',
95
+ message: chalk.yellow(`Provide a unique account key`),
96
+ validate: (input: string) => (input.length > 0 && !existingAccountKeys.includes(input)) || 'Please enter a unique account key',
97
+ },
98
+ {
99
+ type: 'input',
100
+ name: 'address',
101
+ message: chalk.yellow(`What is your account address?`),
102
+ validate: (input: string) => input.length > 0 || 'Please enter a valid address',
103
+ },
104
+ {
105
+ type: 'input',
106
+ name: 'pk',
107
+ message: chalk.yellow(`What is your account private key?`),
108
+ validate: (input: string) => input.length > 0 || 'Please enter a valid pk',
109
+ },
110
+ ]);
111
+
112
+ const address = accountAnswers.address;
113
+ const pk = accountAnswers.pk;
114
+ const account_key = accountAnswers.account_key;
115
+
116
+ store.addAccount(account_key, address, pk);
117
+
118
+ console.log(`${chalk.blue("Account added:")} ${account_key} to network: ${store.config.network}`);
119
+ });
120
+
121
+ program
122
+ .description('List account names of a network')
123
+ .command('list-accounts')
124
+ .action(async (options) => {
125
+ const store = await createStore();
126
+ const accounts = store.listAccounts();
127
+ console.log(`${chalk.blue("Account keys:")} ${accounts.join(', ')}`);
128
+ })
129
+
130
+ program
131
+ .description('List account names of a network')
132
+ .command('get-account')
133
+ .action(async (options) => {
134
+ const store = await createStore();
135
+ const existingAccountKeys = store.listAccounts();
136
+ const accountAnswers = await (<any>inquirer).prompt([
137
+ {
138
+ type: 'input',
139
+ name: 'account_key',
140
+ message: chalk.yellow(`Provide a unique account key`),
141
+ validate: (input: string) => (input.length > 0 && existingAccountKeys.includes(input)) || 'Please enter a value account key',
142
+ },
143
+ ]);
144
+
145
+ const account = store.getAccount(accountAnswers.account_key);
146
+ console.log(`${chalk.blue("Account Address:")} ${account.address}`);
147
+ })
148
+
149
+ // Default action if no command is provided
150
+ program
151
+ .action(() => {
152
+ program.help(); // Show help if no command is provided
153
+ });
154
+
155
+ program.parse(process.argv);
156
+
157
+ // Show help if no command is provided
158
+ if (!process.argv.slice(2).length) {
159
+ program.outputHelp();
160
+ }
@@ -0,0 +1,96 @@
1
+ [
2
+ {
3
+ "data": [
4
+ {
5
+ "name": "previousOwner",
6
+ "type": "felt"
7
+ },
8
+ {
9
+ "name": "newOwner",
10
+ "type": "felt"
11
+ }
12
+ ],
13
+ "keys": [],
14
+ "name": "OwnershipTransferred",
15
+ "type": "event"
16
+ },
17
+ {
18
+ "data": [
19
+ {
20
+ "name": "token",
21
+ "type": "felt"
22
+ },
23
+ {
24
+ "name": "source",
25
+ "type": "felt"
26
+ }
27
+ ],
28
+ "keys": [],
29
+ "name": "TokenSourceChanged",
30
+ "type": "event"
31
+ },
32
+ {
33
+ "name": "constructor",
34
+ "type": "constructor",
35
+ "inputs": [
36
+ {
37
+ "name": "owner",
38
+ "type": "felt"
39
+ }
40
+ ],
41
+ "outputs": []
42
+ },
43
+ {
44
+ "name": "get_price",
45
+ "type": "function",
46
+ "inputs": [
47
+ {
48
+ "name": "token",
49
+ "type": "felt"
50
+ }
51
+ ],
52
+ "outputs": [
53
+ {
54
+ "name": "price",
55
+ "type": "felt"
56
+ }
57
+ ],
58
+ "stateMutability": "view"
59
+ },
60
+ {
61
+ "name": "get_price_with_time",
62
+ "type": "function",
63
+ "inputs": [
64
+ {
65
+ "name": "token",
66
+ "type": "felt"
67
+ }
68
+ ],
69
+ "outputs": [
70
+ {
71
+ "name": "price",
72
+ "type": "felt"
73
+ },
74
+ {
75
+ "name": "update_time",
76
+ "type": "felt"
77
+ }
78
+ ],
79
+ "stateMutability": "view"
80
+ },
81
+ {
82
+ "name": "set_token_source",
83
+ "type": "function",
84
+ "inputs": [
85
+ {
86
+ "name": "token",
87
+ "type": "felt"
88
+ },
89
+ {
90
+ "name": "source",
91
+ "type": "felt"
92
+ }
93
+ ],
94
+ "outputs": []
95
+ }
96
+ ]
@@ -0,0 +1,72 @@
1
+ [
2
+ {
3
+ "name": "Ether",
4
+ "symbol": "ETH",
5
+ "address": "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7",
6
+ "decimals": 18,
7
+ "pricerKey": "ETH-USDT"
8
+ },
9
+ {
10
+ "name": "USD Coin",
11
+ "symbol": "USDC",
12
+ "address": "0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8",
13
+ "decimals": 6,
14
+ "pricerKey": "USDC-USDT"
15
+ },
16
+ {
17
+ "name": "Wrapped BTC",
18
+ "symbol": "WBTC",
19
+ "address": "0x03fe2b97c1fd336e750087d68b9b867997fd64a2661ff3ca5a7c771641e8e7ac",
20
+ "decimals": 8,
21
+ "pricerKey": "WBTC-USDT"
22
+ },
23
+ {
24
+ "name": "Tether USD",
25
+ "symbol": "USDT",
26
+ "address": "0x068f5c6a61780768455de69077e07e89787839bf8166decfbf92b645209c0fb8",
27
+ "decimals": 6,
28
+ "pricerKey": "USDT-USDT"
29
+ },
30
+ {
31
+ "name": "Dai Stablecoin",
32
+ "symbol": "DAIv0",
33
+ "address": "",
34
+ "decimals": 18,
35
+ "pricerKey": "DAI-USDT"
36
+ },
37
+ {
38
+ "name": "Starknet Wrapped Staked Ether",
39
+ "symbol": "wstETH",
40
+ "address": "0x042b8f0484674ca266ac5d08e4ac6a3fe65bd3129795def2dca5c34ecc5f96d2",
41
+ "decimals": 18,
42
+ "pricerKey": "wstETH-USDT"
43
+ },
44
+ {
45
+ "name": "Starknet Token",
46
+ "symbol": "STRK",
47
+ "address": "0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d",
48
+ "decimals": 18,
49
+ "pricerKey": "STRK-USDT"
50
+ },
51
+ {
52
+ "name": "zkLend Token",
53
+ "symbol": "ZEND",
54
+ "address": "",
55
+ "decimals": 18,
56
+ "pricerKey": "ZEND-USDT"
57
+ },
58
+ {
59
+ "name": "Dai Stablecoin",
60
+ "symbol": "DAI",
61
+ "address": "",
62
+ "decimals": 18,
63
+ "pricerKey": "DAI-USDT"
64
+ },
65
+ {
66
+ "name": "Ekubo Protocol",
67
+ "symbol": "EKUBO",
68
+ "address": "",
69
+ "decimals": 18,
70
+ "pricerKey": "DAI-USDT"
71
+ }
72
+ ]
@@ -0,0 +1,38 @@
1
+ import { num } from "starknet";
2
+
3
+ /**
4
+ * A simple wrapper around a contract address that is universally comparable
5
+ * - Helps avoid padding issues
6
+ */
7
+ export class ContractAddr {
8
+ readonly address: string;
9
+
10
+ constructor(address: string) {
11
+ this.address = ContractAddr.standardise(address);
12
+ }
13
+
14
+ static from(address: string) {
15
+ return new ContractAddr(address);
16
+ }
17
+
18
+ eq(other: ContractAddr) {
19
+ return this.address === other.address;
20
+ }
21
+
22
+ eqString(other: string) {
23
+ return this.address === ContractAddr.standardise(other);
24
+ }
25
+
26
+ static standardise(address: string | bigint) {
27
+ let _a = address;
28
+ if (!address) {
29
+ _a = "0";
30
+ }
31
+ const a = num.getHexString(num.getDecimalString(_a.toString()));
32
+ return a;
33
+ }
34
+
35
+ static eqString(a: string, b: string) {
36
+ return ContractAddr.standardise(a) === ContractAddr.standardise(b);
37
+ }
38
+ }
@@ -0,0 +1,53 @@
1
+ import BigNumber from "bignumber.js";
2
+ // import { inspect } from 'util';
3
+ // const customInspectSymbol = inspect.custom || Symbol.for('nodejs.util.inspect.custom');
4
+
5
+ function isNode() {
6
+ // Check for the presence of the `window` object, which is undefined in Node.js
7
+ return typeof window === 'undefined';
8
+ }
9
+
10
+ export class Web3Number extends BigNumber {
11
+ decimals: number;
12
+
13
+ constructor(value: string | number, decimals: number) {
14
+ super(value);
15
+ this.decimals = decimals;
16
+ }
17
+
18
+ static fromWei(weiNumber: string | number, decimals: number) {
19
+ const bn = (new Web3Number(weiNumber, decimals)).dividedBy(10 ** decimals)
20
+ return new Web3Number(bn.toString(), decimals);
21
+ }
22
+
23
+ toWei() {
24
+ return this.mul(10 ** this.decimals).toFixed(0);
25
+ }
26
+
27
+ multipliedBy(value: string | number) {
28
+ return new Web3Number(this.mul(value).toString(), this.decimals);
29
+ }
30
+
31
+ dividedBy(value: string | number) {
32
+ return new Web3Number(this.div(value).toString(), this.decimals);
33
+ }
34
+
35
+ plus(value: string | number) {
36
+ return new Web3Number(this.add(value).toString(), this.decimals);
37
+ }
38
+
39
+ minus(n: number | string, base?: number): Web3Number {
40
+ return new Web3Number(super.minus(n, base).toString(), this.decimals);
41
+ }
42
+
43
+ toString(base?: number | undefined): string {
44
+ return super.toString(base);
45
+ }
46
+
47
+ // [customInspectSymbol](depth: any, inspectOptions: any, inspect: any) {
48
+ // return this.toString();
49
+ // }
50
+ }
51
+
52
+ BigNumber.config({ DECIMAL_PLACES: 18 })
53
+ Web3Number.config({ DECIMAL_PLACES: 18 })
@@ -0,0 +1,2 @@
1
+ export * from './bignumber';
2
+ export * from './address';
package/src/global.ts ADDED
@@ -0,0 +1,73 @@
1
+ import { TokenInfo } from './interfaces';
2
+ import TOKENS from '@/data/tokens.json';
3
+
4
+ const colors = {
5
+ error: 'red',
6
+ warn: 'yellow',
7
+ info: 'blue',
8
+ verbose: 'white',
9
+ debug: 'white',
10
+ }
11
+
12
+ // Add custom colors to Winston
13
+ // winston.addColors(colors);
14
+
15
+ // export const logger = createLogger({
16
+ // level: 'verbose', // Set the minimum logging level
17
+ // format: format.combine(
18
+ // format.colorize({ all: true }), // Apply custom colors
19
+ // format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }), // Add timestamp to log messages
20
+ // format.printf(({ timestamp, level, message }) => {
21
+ // return `${timestamp} ${level}: ${message}`;
22
+ // })
23
+ // ),
24
+ // transports: [
25
+ // // new transports.Console() // Output logs to the console
26
+ // ]
27
+ // });
28
+
29
+
30
+ export const logger = {
31
+ ...console,
32
+ verbose(message: string) {
33
+ console.log(`[VERBOSE] ${message}`);
34
+ }
35
+ };
36
+
37
+
38
+ export class FatalError extends Error {
39
+ constructor(message: string, err?: Error) {
40
+ super(message);
41
+ logger.error(message);
42
+ if (err)
43
+ logger.error(err.message);
44
+ this.name = "FatalError";
45
+ }
46
+ }
47
+ /** Contains globally useful functions.
48
+ * - fatalError: Things to do when a fatal error occurs
49
+ */
50
+ export class Global {
51
+ static fatalError(message: string, err?: Error) {
52
+ logger.error(message);
53
+ console.error(message, err);
54
+ if (err)
55
+ console.error(err);
56
+ process.exit(1);
57
+ }
58
+
59
+ static httpError(url: string, err: Error, message?: string) {
60
+ logger.error(`${url}: ${message}`);
61
+ console.error(err);
62
+ }
63
+
64
+ static async getTokens(): Promise<TokenInfo[]> {
65
+ return TOKENS;
66
+ }
67
+
68
+ static assert(condition: any, message: string) {
69
+ if (!condition) {
70
+ throw new FatalError(message);
71
+ }
72
+ }
73
+ }
@@ -0,0 +1,6 @@
1
+ // contains only browser supported modules
2
+ export * from './modules';
3
+ export * from './interfaces';
4
+ export * from './dataTypes';
5
+ export * from './global';
6
+ export * from './strategies';
package/src/index.ts ADDED
@@ -0,0 +1,9 @@
1
+ // contains all modules that can run in node
2
+ export * from './modules';
3
+ export * from './interfaces';
4
+ export * from './dataTypes';
5
+ export * from './global';
6
+ export * from './strategies';
7
+ export * from './notifs';
8
+ export * from './utils';
9
+ export * from './node';
@@ -0,0 +1,33 @@
1
+ import { BlockIdentifier, RpcProvider } from "starknet"
2
+
3
+ export interface TokenInfo {
4
+ name: string,
5
+ symbol: string,
6
+ address: string,
7
+ decimals: number,
8
+ pricerKey?: string
9
+ }
10
+
11
+ export enum Network {
12
+ mainnet = "mainnet",
13
+ sepolia = "sepolia",
14
+ devnet = "devnet"
15
+ }
16
+
17
+ export interface IConfig {
18
+ provider: RpcProvider,
19
+ network: Network,
20
+ stage: 'production' | 'staging',
21
+ heartbeatUrl?: string
22
+ }
23
+
24
+ export function getMainnetConfig(rpcUrl = "https://starknet-mainnet.public.blastapi.io", blockIdentifier: BlockIdentifier = 'pending'): IConfig {
25
+ return {
26
+ provider: new RpcProvider({
27
+ nodeUrl: rpcUrl,
28
+ blockIdentifier: blockIdentifier
29
+ }),
30
+ stage: "production",
31
+ network: Network.mainnet
32
+ }
33
+ }
@@ -0,0 +1,3 @@
1
+ export * from './lending';
2
+ export * from './common';
3
+ export * from './initializable';
@@ -0,0 +1,21 @@
1
+ export abstract class Initializable {
2
+ protected initialized: boolean;
3
+
4
+ constructor() {
5
+ this.initialized = false;
6
+ }
7
+
8
+ abstract init(): Promise<void>;
9
+
10
+ async waitForInitilisation() {
11
+ return new Promise<void>((resolve, reject) => {
12
+ const interval = setInterval(() => {
13
+ if (this.initialized) {
14
+ console.log('Initialised');
15
+ clearInterval(interval);
16
+ resolve();
17
+ }
18
+ }, 1000);
19
+ });
20
+ }
21
+ }