Skip to content

Commit f72733d

Browse files
authored
Merge pull request #2 from allen0x1/dev
Dev
2 parents 7be11df + 4eb2322 commit f72733d

File tree

8 files changed

+43
-52
lines changed

8 files changed

+43
-52
lines changed

.env-example

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
RPC_ENDPOINT="https://ssc-dao.genesysgo.net"
2+
WALLET_PRIVATE_KEY=abc123def456

README.md

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,25 +5,19 @@ This code was made to experiment and learn. It has not been thoroughly tested an
55

66
Based on the [Jupiter Core Example](https://github.com/jup-ag/jupiter-core-example)
77

8+
![Jup DCA Bot Demo](img/demo.gif)
9+
810
## Install
911
```
1012
yarn install
1113
```
1214
## Configure
13-
Create an `.env` file to store private info. Add the variables below.
14-
```
15-
CLUSTER=mainnet-beta
16-
WALLET_PRIVATE_KEY=abc123def456
17-
```
18-
Create your own `dcaconfig.ts`. See `dcaconfig-example.ts` for a template.
15+
1. Create an `.env` file at the project root. See `.env-example`.
16+
Private key can be obtained from Phantom via Settings -> Export Private Key.
17+
2. Create your own `dcaconfig.ts`. See `dcaconfig-example.ts` for a template.
1918

2019
To see example cron expressions, check out [crontab.guru](https://crontab.guru/).
2120
## Run
2221
```
2322
yarn start
2423
```
25-
## Development
26-
```
27-
yarn add --dev node-cron
28-
yarn add --dev @types/node-cron
29-
```

img/demo.gif

79.9 KB
Loading

package.json

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "jup-dca-bot",
3-
"version": "1.0.0",
4-
"description": "dollar cost averaging bot",
3+
"version": "0.1.0",
4+
"description": "Dollar cost averaging bot on Solana",
55
"source": "src/index.ts",
66
"main": "src/index.ts",
77
"module": "dist/module.js",
@@ -15,18 +15,19 @@
1515
"dependencies": {
1616
"@jup-ag/core": "^1.0.0-beta.16",
1717
"@solana/wallet-adapter-base": "^0.7.1",
18+
"@solana/web3.js": "^1.36.0",
1819
"@types/bs58": "^4.0.1",
1920
"@types/isomorphic-fetch": "^0.0.35",
2021
"bs58": "^4.0.1",
22+
"cronstrue": "^1.125.0",
2123
"dotenv": "^10.0.0",
2224
"isomorphic-fetch": "^3.0.0",
23-
"node-fetch": "^3.1.0",
24-
"ts-node": "^10.4.0"
25+
"node-cron": "^3.0.0",
26+
"node-fetch": "^3.1.0"
2527
},
2628
"devDependencies": {
27-
"@solana/web3.js": "^1.36.0",
2829
"@types/node-cron": "^3.0.1",
29-
"node-cron": "^3.0.0",
30+
"ts-node": "^10.7.0",
3031
"typescript": "^4.5.3"
3132
},
3233
"resolutions": {

src/constants/index.ts

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,8 @@
1-
import { Cluster, Keypair } from "@solana/web3.js";
1+
import { Keypair } from "@solana/web3.js";
22
import bs58 from "bs58";
3-
43
import 'dotenv/config'
54

6-
// Endpoints, connection
7-
export const ENV: Cluster = (process.env.CLUSTER as Cluster) || "mainnet-beta";
8-
9-
// Sometimes, your RPC endpoint may reject you if you spam too many RPC calls. Sometimes, your PRC server
10-
// may have invalid cache and cause problems.
11-
export const SOLANA_RPC_ENDPOINT =
12-
ENV === "devnet"
13-
? "https://api.devnet.solana.com"
14-
: "https://ssc-dao.genesysgo.net";
5+
export const SOLANA_RPC_ENDPOINT: string = process.env.RPC_ENDPOINT!;
156

167
// Wallets
178
export const WALLET_PRIVATE_KEY =

src/dcaconfig-example.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,4 @@ export const dcaconfig: DcaConfig[] = [
2929
slippage: 1,
3030
cron: "* * * * *"
3131
},
32-
];
32+
];

src/index.ts

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,9 @@
11
import fetch from "isomorphic-fetch";
2-
import { Jupiter, RouteInfo, TOKEN_LIST_URL } from "@jup-ag/core";
2+
import { Jupiter, TOKEN_LIST_URL } from "@jup-ag/core";
33
import { PublicKey, Connection } from "@solana/web3.js";
44
import * as cron from "node-cron";
5-
import {
6-
ENV,
7-
MINT_ADDRESSES,
8-
SOLANA_RPC_ENDPOINT,
9-
Token,
10-
USER_KEYPAIR,
11-
} from "./constants";
5+
import cronstrue from "cronstrue";
6+
import {Token, MINT_ADDRESSES, USER_KEYPAIR, SOLANA_RPC_ENDPOINT} from "./constants";
127
import { dcaconfig } from './dcaconfig'
138

149
const jupiterSwap = async ({
@@ -61,11 +56,11 @@ const jupiterSwap = async ({
6156
process.stdout.write(
6257
`${swapResult.outputAmount / (10 ** inputToken.decimals)} `
6358
);
64-
process.stdout.write(`${outputToken.symbol} -> `);
59+
process.stdout.write(`${outputToken.symbol}: `);
6560
console.log(`https://solscan.io/tx/${swapResult.txid}`);
6661
}
6762
} else {
68-
console.log("Error: Jupiter couldn't route.");
63+
console.log("Error during jupiter.computeRoutes().");
6964
}
7065
} catch (error) {
7166
throw error;
@@ -74,33 +69,36 @@ const jupiterSwap = async ({
7469

7570
const main = async () => {
7671
try {
77-
const connection = new Connection(SOLANA_RPC_ENDPOINT); // Setup Solana
72+
console.log("Starting Jupiter DCA Bot");
73+
74+
const cluster = "mainnet-beta"; // Force mainnet, as this uses Jupiter which is not deployed on devnet/testnet
75+
const connection = new Connection(SOLANA_RPC_ENDPOINT);
7876
const jupiter = await Jupiter.load({
7977
connection,
80-
cluster: ENV,
81-
user: USER_KEYPAIR, // or public key
78+
cluster: cluster,
79+
user: USER_KEYPAIR,
8280
});
8381

8482
// Fetch token list from Jupiter API
85-
const tokens: Token[] = await (await fetch(TOKEN_LIST_URL[ENV])).json();
83+
const tokens: Token[] = await (await fetch(TOKEN_LIST_URL[cluster])).json();
8684

87-
console.log("Validating dcaconfig.");
88-
console.log("A job may be excluded because:");
85+
console.log("Warning! dcaconfig entries may be excluded due to:");
8986
console.log("- invalid cron expression");
9087
console.log("- inputToken or outputToken does not exist in MINT_ADDRESSES");
88+
console.log("Validating dcaconfig.ts ...");
9189
const filteredJobs = dcaconfig.filter(job => {
9290
return (cron.validate(job.cron)
9391
&& job.inputToken in MINT_ADDRESSES
9492
&& job.outputToken in MINT_ADDRESSES
9593
);
9694
});
9795

98-
console.log("Scheduling the following jobs: ");
96+
console.log("Scheduling swaps:");
9997
filteredJobs.map(job => {
100-
console.log(`${job.amount} ${job.inputToken} -> ${job.outputToken}. cron: ${job.cron}`);
98+
console.log(`${job.amount} ${job.inputToken} for ${job.outputToken} ${cronstrue.toString(job.cron)}`);
10199
});
102100

103-
const scheduledJobs = filteredJobs.map(job => {
101+
filteredJobs.forEach(job => {
104102
const inputToken = tokens.find((t) =>
105103
t.address == MINT_ADDRESSES[job.inputToken]
106104
);

yarn.lock

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -557,6 +557,11 @@ create-require@^1.1.0:
557557
resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333"
558558
integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==
559559

560+
cronstrue@^1.125.0:
561+
version "1.125.0"
562+
resolved "https://registry.yarnpkg.com/cronstrue/-/cronstrue-1.125.0.tgz#8030816d033d00caade9b2a9f9b71e69175bcf42"
563+
integrity sha512-qkC5mVbVGuuyBVXmam5anaRtbLcgfBUKajoyZqCdf/XBdgF43PsLSEm8eEi2dsI3YbqDPbLSH2mWNzM1dVqHgQ==
564+
560565
cross-fetch@3.0.6:
561566
version "3.0.6"
562567
resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.0.6.tgz#3a4040bc8941e653e0e9cf17f29ebcd177d3365c"
@@ -1235,10 +1240,10 @@ traverse-chain@~0.1.0:
12351240
resolved "https://registry.yarnpkg.com/traverse-chain/-/traverse-chain-0.1.0.tgz#61dbc2d53b69ff6091a12a168fd7d433107e40f1"
12361241
integrity sha1-YdvC1Ttp/2CRoSoWj9fUMxB+QPE=
12371242

1238-
ts-node@^10.4.0:
1239-
version "10.6.0"
1240-
resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.6.0.tgz#c3f4195d5173ce3affdc8f2fd2e9a7ac8de5376a"
1241-
integrity sha512-CJen6+dfOXolxudBQXnVjRVvYTmTWbyz7cn+xq2XTsvnaXbHqr4gXSCNbS2Jj8yTZMuGwUoBESLaOkLascVVvg==
1243+
ts-node@^10.7.0:
1244+
version "10.7.0"
1245+
resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.7.0.tgz#35d503d0fab3e2baa672a0e94f4b40653c2463f5"
1246+
integrity sha512-TbIGS4xgJoX2i3do417KSaep1uRAW/Lu+WAL2doDHC0D6ummjirVOXU5/7aiZotbQ5p1Zp9tP7U6cYhA0O7M8A==
12421247
dependencies:
12431248
"@cspotcode/source-map-support" "0.7.0"
12441249
"@tsconfig/node10" "^1.0.7"

0 commit comments

Comments
 (0)