@slvr-labs/sdk 0.1.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/LICENSE +21 -0
- package/README.md +849 -0
- package/dist/connect.d.ts +47 -0
- package/dist/connect.d.ts.map +1 -0
- package/dist/connect.js +56 -0
- package/dist/connect.js.map +1 -0
- package/dist/contracts/autoCommit.d.ts +151 -0
- package/dist/contracts/autoCommit.d.ts.map +1 -0
- package/dist/contracts/autoCommit.js +426 -0
- package/dist/contracts/autoCommit.js.map +1 -0
- package/dist/contracts/hub.d.ts +50 -0
- package/dist/contracts/hub.d.ts.map +1 -0
- package/dist/contracts/hub.js +118 -0
- package/dist/contracts/hub.js.map +1 -0
- package/dist/contracts/index.d.ts +8 -0
- package/dist/contracts/index.d.ts.map +1 -0
- package/dist/contracts/index.js +18 -0
- package/dist/contracts/index.js.map +1 -0
- package/dist/contracts/jackpot.d.ts +21 -0
- package/dist/contracts/jackpot.d.ts.map +1 -0
- package/dist/contracts/jackpot.js +44 -0
- package/dist/contracts/jackpot.js.map +1 -0
- package/dist/contracts/lottery.d.ts +256 -0
- package/dist/contracts/lottery.d.ts.map +1 -0
- package/dist/contracts/lottery.js +767 -0
- package/dist/contracts/lottery.js.map +1 -0
- package/dist/contracts/registry.d.ts +53 -0
- package/dist/contracts/registry.d.ts.map +1 -0
- package/dist/contracts/registry.js +143 -0
- package/dist/contracts/registry.js.map +1 -0
- package/dist/contracts/staking.d.ts +101 -0
- package/dist/contracts/staking.d.ts.map +1 -0
- package/dist/contracts/staking.js +306 -0
- package/dist/contracts/staking.js.map +1 -0
- package/dist/contracts/token.d.ts +95 -0
- package/dist/contracts/token.d.ts.map +1 -0
- package/dist/contracts/token.js +273 -0
- package/dist/contracts/token.js.map +1 -0
- package/dist/deployments.d.ts +117 -0
- package/dist/deployments.d.ts.map +1 -0
- package/dist/deployments.js +74 -0
- package/dist/deployments.js.map +1 -0
- package/dist/errors.d.ts +39 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +67 -0
- package/dist/errors.js.map +1 -0
- package/dist/ev.d.ts +123 -0
- package/dist/ev.d.ts.map +1 -0
- package/dist/ev.js +111 -0
- package/dist/ev.js.map +1 -0
- package/dist/events.d.ts +418 -0
- package/dist/events.d.ts.map +1 -0
- package/dist/events.js +87 -0
- package/dist/events.js.map +1 -0
- package/dist/index.d.ts +248 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +436 -0
- package/dist/index.js.map +1 -0
- package/dist/oracle.d.ts +48 -0
- package/dist/oracle.d.ts.map +1 -0
- package/dist/oracle.js +77 -0
- package/dist/oracle.js.map +1 -0
- package/dist/price.d.ts +52 -0
- package/dist/price.d.ts.map +1 -0
- package/dist/price.js +78 -0
- package/dist/price.js.map +1 -0
- package/dist/transaction.d.ts +54 -0
- package/dist/transaction.d.ts.map +1 -0
- package/dist/transaction.js +105 -0
- package/dist/transaction.js.map +1 -0
- package/dist/types.d.ts +162 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +23 -0
- package/dist/types.js.map +1 -0
- package/dist/utils.d.ts +58 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +110 -0
- package/dist/utils.js.map +1 -0
- package/examples/.env.example +22 -0
- package/examples/README.md +417 -0
- package/examples/automated-betting.ts +232 -0
- package/examples/combined-strategy.ts +227 -0
- package/examples/constants.ts +35 -0
- package/examples/custom-strategy-example.ts +231 -0
- package/examples/expected-value-strategy.ts +255 -0
- package/examples/fixed-squares-strategy.ts +176 -0
- package/examples/index.ts +30 -0
- package/examples/least-allocated-strategy.ts +224 -0
- package/examples/local-test.ts +172 -0
- package/examples/quickstart-bet.ts +72 -0
- package/examples/quickstart-read.ts +87 -0
- package/examples/simple-example.ts +122 -0
- package/examples/strategy-base.ts +283 -0
- package/package.json +71 -0
- package/skills/slvr-bot/SKILL.md +193 -0
- package/skills/slvr-bot/references/api.md +117 -0
|
@@ -0,0 +1,417 @@
|
|
|
1
|
+
# Slvr SDK Examples
|
|
2
|
+
|
|
3
|
+
This directory contains reference implementations demonstrating how to use the Slvr SDK for various betting strategies and automation.
|
|
4
|
+
|
|
5
|
+
> **How to use these:** they are reference code, not part of the importable API.
|
|
6
|
+
> Copy the file(s) you want into your own project and change the relative
|
|
7
|
+
> `../src` import at the top of each file to `@slvr-labs/sdk`. The import paths in the
|
|
8
|
+
> snippets below (e.g. `from './fixed-squares-strategy'`) assume you've copied
|
|
9
|
+
> the example files alongside your own code.
|
|
10
|
+
|
|
11
|
+
## Getting Started
|
|
12
|
+
|
|
13
|
+
Brand new to the SDK? Run these two first β they use the addresses and chain that
|
|
14
|
+
ship with the SDK (`deployments.robinhood` + `robinhoodChain`), so there's nothing
|
|
15
|
+
to configure.
|
|
16
|
+
|
|
17
|
+
### `quickstart-read.ts` β read-only tour (no wallet)
|
|
18
|
+
|
|
19
|
+
The fastest way to confirm everything works. Needs only an RPC β no private key.
|
|
20
|
+
Prints the current round, pot, and the SLVR price in **both ETH and USD**.
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npx ts-node quickstart-read.ts
|
|
24
|
+
npx ts-node quickstart-read.ts 0xYourAddress # also show that address's balance + bets
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### `quickstart-bet.ts` β place a bet (wallet)
|
|
28
|
+
|
|
29
|
+
The minimal write path: builds a wallet-backed SDK, checks the round's expected
|
|
30
|
+
value, places one small bet, and shows how to claim after the round resolves. Bets
|
|
31
|
+
are paid in native ETH β no token approval needed.
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
PRIVATE_KEY=0xabc... npx ts-node quickstart-bet.ts
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
> Start with a small stake (the example defaults to 0.002 ETH). You can only claim
|
|
38
|
+
> a round you won and haven't already claimed.
|
|
39
|
+
|
|
40
|
+
## Strategy System
|
|
41
|
+
|
|
42
|
+
The SDK includes a flexible strategy system that makes it easy to create custom betting strategies. All strategies extend the `BettingStrategy` base class, which handles:
|
|
43
|
+
- Round monitoring
|
|
44
|
+
- Threshold checking
|
|
45
|
+
- Error handling
|
|
46
|
+
- Bet execution
|
|
47
|
+
|
|
48
|
+
### Creating Custom Strategies
|
|
49
|
+
|
|
50
|
+
Extend `BettingStrategy` and override these methods:
|
|
51
|
+
- `selectSquares()` - Choose which squares to bet on
|
|
52
|
+
- `calculateAmounts()` - Calculate bet amounts for each square
|
|
53
|
+
- `shouldBet()` - Optional: Add custom conditions for betting
|
|
54
|
+
- `onBetPlaced()` - Optional: Handle successful bets
|
|
55
|
+
- `onError()` - Optional: Custom error handling
|
|
56
|
+
|
|
57
|
+
### Example: Fixed Squares Strategy
|
|
58
|
+
|
|
59
|
+
The simplest strategy - bet on the same squares every round:
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
import { FixedSquaresStrategy } from './fixed-squares-strategy';
|
|
63
|
+
import { parseEther } from 'viem';
|
|
64
|
+
|
|
65
|
+
const strategy = new FixedSquaresStrategy(sdk, {
|
|
66
|
+
squares: [0, 5, 10, 15, 20], // Bet on these squares
|
|
67
|
+
amountPerSquare: parseEther('1'), // 1 ETH per square
|
|
68
|
+
threshold: parseEther('100'), // Only bet when round < 100 ETH
|
|
69
|
+
checkInterval: 5000, // Check every 5 seconds
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
await strategy.start();
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Example: Custom Strategy
|
|
76
|
+
|
|
77
|
+
```typescript
|
|
78
|
+
import { BettingStrategy } from './strategy-base';
|
|
79
|
+
|
|
80
|
+
class MyCustomStrategy extends BettingStrategy {
|
|
81
|
+
protected async selectSquares(roundId: bigint): Promise<number[]> {
|
|
82
|
+
// Your logic to select squares
|
|
83
|
+
return [0, 1, 2, 3, 4];
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
protected async calculateAmounts(
|
|
87
|
+
roundId: bigint,
|
|
88
|
+
round: any,
|
|
89
|
+
squares: number[]
|
|
90
|
+
): Promise<bigint[]> {
|
|
91
|
+
// Your logic to calculate amounts
|
|
92
|
+
return squares.map(() => parseEther('1'));
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const strategy = new MyCustomStrategy(sdk, {
|
|
97
|
+
threshold: parseEther('100'),
|
|
98
|
+
checkInterval: 5000,
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
await strategy.start();
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Examples
|
|
105
|
+
|
|
106
|
+
### 1. Fixed Squares Strategy (`fixed-squares-strategy.ts`)
|
|
107
|
+
|
|
108
|
+
Bet on a fixed set of squares every round when threshold is met.
|
|
109
|
+
|
|
110
|
+
**Usage:**
|
|
111
|
+
```typescript
|
|
112
|
+
import { FixedSquaresStrategy } from './fixed-squares-strategy';
|
|
113
|
+
import { parseEther } from 'viem';
|
|
114
|
+
|
|
115
|
+
const strategy = new FixedSquaresStrategy(sdk, {
|
|
116
|
+
squares: [0, 5, 10, 15, 20],
|
|
117
|
+
amountPerSquare: parseEther('1'),
|
|
118
|
+
threshold: parseEther('100'),
|
|
119
|
+
checkInterval: 5000,
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
await strategy.start();
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### 3. Automated Betting Bot (`automated-betting.ts`)
|
|
126
|
+
|
|
127
|
+
A bot that automatically monitors rounds and places bets when the total wager is below a threshold (e.g., 100 ETH). It distributes bets across squares with the least allocation.
|
|
128
|
+
|
|
129
|
+
**Features:**
|
|
130
|
+
- Monitors rounds at configurable intervals
|
|
131
|
+
- Automatically bets when total wager < threshold
|
|
132
|
+
- Targets squares with least allocation
|
|
133
|
+
- Configurable bet amounts and square counts
|
|
134
|
+
|
|
135
|
+
**Usage:**
|
|
136
|
+
```typescript
|
|
137
|
+
import { AutomatedBettingBot } from './automated-betting';
|
|
138
|
+
import { parseEther } from 'viem';
|
|
139
|
+
|
|
140
|
+
const bot = new AutomatedBettingBot(sdk, {
|
|
141
|
+
threshold: parseEther('100'), // Bet when round has < 100 ETH
|
|
142
|
+
betAmount: parseEther('1'), // 1 ETH per square
|
|
143
|
+
minSquares: 3,
|
|
144
|
+
maxSquares: 5,
|
|
145
|
+
checkInterval: 5000, // Check every 5 seconds
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
await bot.start();
|
|
149
|
+
// ... later
|
|
150
|
+
bot.stop();
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### 2. Least Allocated Strategy (`least-allocated-strategy.ts`)
|
|
154
|
+
|
|
155
|
+
A strategy class that helps identify and bet on squares with the least funds allocated.
|
|
156
|
+
|
|
157
|
+
**Features:**
|
|
158
|
+
- Get squares sorted by allocation
|
|
159
|
+
- Calculate optimal bet distribution
|
|
160
|
+
- Analyze round allocation patterns
|
|
161
|
+
- Place bets on least allocated squares
|
|
162
|
+
|
|
163
|
+
**Usage:**
|
|
164
|
+
```typescript
|
|
165
|
+
import { LeastAllocatedStrategy } from './least-allocated-strategy';
|
|
166
|
+
import { parseEther } from 'viem';
|
|
167
|
+
|
|
168
|
+
const strategy = new LeastAllocatedStrategy(sdk);
|
|
169
|
+
const roundId = await sdk.lottery.currentRoundId();
|
|
170
|
+
|
|
171
|
+
// Analyze the round
|
|
172
|
+
const analysis = await strategy.analyzeRound(roundId);
|
|
173
|
+
console.log('Least allocated:', analysis.leastAllocated);
|
|
174
|
+
|
|
175
|
+
// Place a bet
|
|
176
|
+
const txHash = await strategy.betOnLeastAllocated(
|
|
177
|
+
roundId,
|
|
178
|
+
parseEther('5'), // 5 ETH total
|
|
179
|
+
5 // Bet on 5 squares
|
|
180
|
+
);
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### 4. Combined Strategy (`combined-strategy.ts`)
|
|
184
|
+
|
|
185
|
+
Combines both strategies: monitors for low total wager AND bets on least allocated squares.
|
|
186
|
+
|
|
187
|
+
**Features:**
|
|
188
|
+
- Monitors rounds for total wager < threshold
|
|
189
|
+
- Automatically identifies least allocated squares
|
|
190
|
+
- Provides detailed logging and analysis
|
|
191
|
+
- Configurable parameters
|
|
192
|
+
|
|
193
|
+
**Usage:**
|
|
194
|
+
```typescript
|
|
195
|
+
import { CombinedBettingBot } from './combined-strategy';
|
|
196
|
+
import { parseEther } from 'viem';
|
|
197
|
+
|
|
198
|
+
const bot = new CombinedBettingBot(sdk, {
|
|
199
|
+
threshold: parseEther('100'), // Bet when < 100 ETH
|
|
200
|
+
betAmount: parseEther('5'), // 5 ETH total bet
|
|
201
|
+
squareCount: 5, // Bet on 5 least allocated squares
|
|
202
|
+
checkInterval: 5000, // Check every 5 seconds
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
await bot.start();
|
|
206
|
+
// ... later
|
|
207
|
+
bot.stop();
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
### 6. Expected-Value Bot (`expected-value-strategy.ts`)
|
|
211
|
+
|
|
212
|
+
The most "quant" example: it **only bets when the round is positive expected
|
|
213
|
+
value**. It uses the SDK's built-in grid-mining calculator (`sdk.estimateRoundEv`
|
|
214
|
+
/ `computeGridMiningEv`) and SLVR price reader (`sdk.price`), so its math matches
|
|
215
|
+
the protocol's own edge calculator.
|
|
216
|
+
|
|
217
|
+
**How it decides:** the winning square is drawn uniformly, so mining SLVR only
|
|
218
|
+
pays while the pot is small enough that your SLVR reward beats the ETH you bleed
|
|
219
|
+
to the protocol fee. The bot computes net EV per round and bets when it clears a
|
|
220
|
+
threshold β otherwise it waits for the pot to shrink or SLVR to rise.
|
|
221
|
+
|
|
222
|
+
**Features:**
|
|
223
|
+
- Live pot / emission / SLVR price pulled on-chain each round
|
|
224
|
+
- Logs the full EV breakdown (share, SLVR mined, ETH bleed, jackpot, net, break-even pot)
|
|
225
|
+
- Bets only on +EV rounds, covering the grid proportionally so it holds the winner
|
|
226
|
+
- Hold vs cash-out mode (accounts for the 10% refining fee when cashing SLVR to ETH)
|
|
227
|
+
|
|
228
|
+
**Usage:**
|
|
229
|
+
```typescript
|
|
230
|
+
import { ExpectedValueBot } from './expected-value-strategy';
|
|
231
|
+
|
|
232
|
+
const bot = new ExpectedValueBot(sdk, {
|
|
233
|
+
stakeEth: 0.1, // commit 0.1 ETH per +EV round
|
|
234
|
+
minNetEth: 0, // bet on any positive-EV round (raise to demand more edge)
|
|
235
|
+
cashOut: false, // value mined SLVR at full price (holding/staking it)
|
|
236
|
+
// ethUsd: 1815, // optional override; otherwise the Chainlink feed is used
|
|
237
|
+
checkInterval: 5000,
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
await bot.start();
|
|
241
|
+
// ... later
|
|
242
|
+
bot.stop();
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
The bot logs the SLVR price in **both ETH and USD**. USD comes from the SDK's
|
|
246
|
+
Chainlink ETH/USD feed (`sdk.ethUsd`), which is wired for Robinhood Chain, so USD
|
|
247
|
+
shows automatically. Pass `ethUsd` (or run with `ETH_USD=1815 β¦`) to override it,
|
|
248
|
+
or on a chain without a feed.
|
|
249
|
+
|
|
250
|
+
> Requires a `slvrEthPair` address so `sdk.price` works β it's included in
|
|
251
|
+
> `deployments.robinhood.addresses`, which this example uses.
|
|
252
|
+
|
|
253
|
+
## Running Examples
|
|
254
|
+
|
|
255
|
+
### 1. Install dependencies
|
|
256
|
+
|
|
257
|
+
From the `sdk/ts` directory:
|
|
258
|
+
|
|
259
|
+
```bash
|
|
260
|
+
npm install
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
### 2. Run an example
|
|
264
|
+
|
|
265
|
+
The examples are TypeScript. The simplest way to run one is with `ts-node` via
|
|
266
|
+
`npx` (it's fetched on demand β no global install needed):
|
|
267
|
+
|
|
268
|
+
```bash
|
|
269
|
+
# Read-only β needs nothing but an internet connection:
|
|
270
|
+
npx ts-node examples/quickstart-read.ts
|
|
271
|
+
|
|
272
|
+
# Pass an address to also see its balance/bets:
|
|
273
|
+
npx ts-node examples/quickstart-read.ts 0xYourAddress
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
> Prefer to compile? `npx tsc` then `node dist-examples/...` also works. `ts-node`
|
|
277
|
+
> just skips the build step.
|
|
278
|
+
|
|
279
|
+
### 3. Add a private key (only for examples that bet)
|
|
280
|
+
|
|
281
|
+
Read-only examples (like `quickstart-read.ts`) need **no key**. Examples that send
|
|
282
|
+
transactions read your key from the `PRIVATE_KEY` environment variable. The
|
|
283
|
+
simplest, most reliable way is to set it inline for the one command:
|
|
284
|
+
|
|
285
|
+
```bash
|
|
286
|
+
PRIVATE_KEY=0xabc123... npx ts-node examples/quickstart-bet.ts
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
Or keep it in a file: copy `.env.example` to `.env`, put your key in it, then load
|
|
290
|
+
it into your shell before running (the examples don't auto-load `.env`):
|
|
291
|
+
|
|
292
|
+
```bash
|
|
293
|
+
cp .env.example .env # then edit .env and paste your key
|
|
294
|
+
set -a; source .env; set +a # load it into the environment
|
|
295
|
+
npx ts-node examples/quickstart-bet.ts
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
**Key safety β please read:**
|
|
299
|
+
- Use a **fresh / burner** key, not one holding real value.
|
|
300
|
+
- The account needs a **small amount of ETH on Robinhood Chain** β for gas, plus
|
|
301
|
+
whatever you bet.
|
|
302
|
+
- **Never commit your key.** `.env` is git-ignored here; only `.env.example`
|
|
303
|
+
(which has a dummy key) is tracked. Setting the key inline avoids a file entirely.
|
|
304
|
+
|
|
305
|
+
### 4. (Optional) Point at a custom deployment
|
|
306
|
+
|
|
307
|
+
`examples/constants.ts` defaults to the canonical Robinhood Chain mainnet addresses
|
|
308
|
+
that ship with the SDK (`deployments.robinhood`). Edit it only to target a local or
|
|
309
|
+
custom deployment.
|
|
310
|
+
|
|
311
|
+
### Environment Variables
|
|
312
|
+
|
|
313
|
+
- `PRIVATE_KEY` β your wallet key, hex with `0x` prefix. Required only for examples
|
|
314
|
+
that send transactions; read-only examples ignore it.
|
|
315
|
+
- `ETH_USD` β optional ETH/USD override for USD display (otherwise the on-chain
|
|
316
|
+
Chainlink feed is used).
|
|
317
|
+
|
|
318
|
+
### Basic Setup
|
|
319
|
+
|
|
320
|
+
All examples use the constants file and environment variables:
|
|
321
|
+
|
|
322
|
+
```typescript
|
|
323
|
+
import { createPublicClient, createWalletClient, http } from 'viem';
|
|
324
|
+
import { privateKeyToAccount } from 'viem/accounts';
|
|
325
|
+
import { SlvrSDK } from '@slvr-labs/sdk';
|
|
326
|
+
import { CONTRACTS, ROBINHOOD_CHAIN } from './constants';
|
|
327
|
+
|
|
328
|
+
// ROBINHOOD_CHAIN is already a viem `Chain` β no need to wrap it.
|
|
329
|
+
const publicClient = createPublicClient({
|
|
330
|
+
chain: ROBINHOOD_CHAIN,
|
|
331
|
+
transport: http(),
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
// Get private key from environment
|
|
335
|
+
const privateKey = process.env.PRIVATE_KEY;
|
|
336
|
+
if (!privateKey) {
|
|
337
|
+
throw new Error('PRIVATE_KEY environment variable is required');
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
const account = privateKeyToAccount(privateKey as `0x${string}`);
|
|
341
|
+
const walletClient = createWalletClient({
|
|
342
|
+
chain: ROBINHOOD_CHAIN,
|
|
343
|
+
transport: http(),
|
|
344
|
+
account,
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
// Initialize SDK with contract addresses from constants
|
|
348
|
+
const sdk = new SlvrSDK({
|
|
349
|
+
publicClient,
|
|
350
|
+
walletClient,
|
|
351
|
+
addresses: {
|
|
352
|
+
lottery: CONTRACTS.LOTTERY,
|
|
353
|
+
staking: CONTRACTS.STAKING,
|
|
354
|
+
token: CONTRACTS.TOKEN,
|
|
355
|
+
autoCommit: CONTRACTS.AUTO_COMMIT !== '0x...' ? CONTRACTS.AUTO_COMMIT : undefined,
|
|
356
|
+
},
|
|
357
|
+
});
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
### 5. Custom Strategy Examples (`custom-strategy-example.ts`)
|
|
361
|
+
|
|
362
|
+
Several example custom strategies showing different approaches:
|
|
363
|
+
- `LeastAllocatedCustomStrategy` - Bet on squares with least allocation
|
|
364
|
+
- `RandomSquaresStrategy` - Bet on random squares
|
|
365
|
+
- `MostBettorsStrategy` - Bet on squares with most bettors (social proof)
|
|
366
|
+
- `WeightedAllocationStrategy` - Weight bets inversely by allocation
|
|
367
|
+
- `ConditionalStrategy` - Only bet when certain conditions are met
|
|
368
|
+
|
|
369
|
+
## Strategy Ideas
|
|
370
|
+
|
|
371
|
+
You can easily create your own strategies by extending `BettingStrategy`:
|
|
372
|
+
|
|
373
|
+
### 1. Equal Distribution Strategy
|
|
374
|
+
Bet equal amounts on all 25 squares to maximize coverage.
|
|
375
|
+
|
|
376
|
+
### 2. Historical Analysis
|
|
377
|
+
Analyze past rounds to identify patterns and bet accordingly.
|
|
378
|
+
|
|
379
|
+
### 3. Multi-Round Strategy
|
|
380
|
+
Spread bets across multiple rounds to diversify risk.
|
|
381
|
+
|
|
382
|
+
### 4. Time-Based Strategy
|
|
383
|
+
Adjust betting based on time remaining in the round.
|
|
384
|
+
|
|
385
|
+
### 5. Portfolio Strategy
|
|
386
|
+
Diversify across multiple strategies simultaneously.
|
|
387
|
+
|
|
388
|
+
## Safety Considerations
|
|
389
|
+
|
|
390
|
+
β οΈ **Important:** These examples are for educational purposes. When running automated bots:
|
|
391
|
+
|
|
392
|
+
1. **Test on testnet first** - Never run untested code on mainnet
|
|
393
|
+
2. **Set reasonable limits** - Don't bet more than you can afford to lose
|
|
394
|
+
3. **Monitor gas costs** - Frequent transactions can be expensive
|
|
395
|
+
4. **Handle errors gracefully** - Network issues can cause failures
|
|
396
|
+
5. **Respect rate limits** - Don't spam the network
|
|
397
|
+
6. **Secure your keys** - Never expose private keys in code
|
|
398
|
+
|
|
399
|
+
## Customization
|
|
400
|
+
|
|
401
|
+
All examples are designed to be easily customizable. You can:
|
|
402
|
+
|
|
403
|
+
- Adjust thresholds and amounts
|
|
404
|
+
- Modify square selection logic
|
|
405
|
+
- Add additional conditions
|
|
406
|
+
- Integrate with other services (notifications, analytics, etc.)
|
|
407
|
+
- Combine multiple strategies
|
|
408
|
+
|
|
409
|
+
## Contributing
|
|
410
|
+
|
|
411
|
+
Feel free to create your own examples and share them! Common patterns include:
|
|
412
|
+
- Integration with notification services
|
|
413
|
+
- Database logging
|
|
414
|
+
- Analytics and reporting
|
|
415
|
+
- Multi-account management
|
|
416
|
+
- Advanced risk management
|
|
417
|
+
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Example: Automated betting strategy
|
|
3
|
+
*
|
|
4
|
+
* This example demonstrates how to:
|
|
5
|
+
* 1. Monitor rounds and automatically bet when total wager is less than 100 ETH
|
|
6
|
+
* 2. Bet on squares with the least funds allocated
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { SlvrSDK } from '../src';
|
|
10
|
+
import { PublicClient, WalletClient, parseEther } from 'viem';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Automated betting bot that bets when round has less than threshold ETH
|
|
14
|
+
* and distributes bets across squares with least allocation
|
|
15
|
+
*/
|
|
16
|
+
export class AutomatedBettingBot {
|
|
17
|
+
private sdk: SlvrSDK;
|
|
18
|
+
private threshold: bigint; // Minimum total wager threshold (e.g., 100 ETH)
|
|
19
|
+
private betAmount: bigint; // Amount to bet per square
|
|
20
|
+
private minSquares: number; // Minimum number of squares to bet on
|
|
21
|
+
private maxSquares: number; // Maximum number of squares to bet on
|
|
22
|
+
private checkInterval: number; // How often to check (in milliseconds)
|
|
23
|
+
private isRunning: boolean = false;
|
|
24
|
+
private intervalId?: NodeJS.Timeout;
|
|
25
|
+
|
|
26
|
+
constructor(
|
|
27
|
+
sdk: SlvrSDK,
|
|
28
|
+
options: {
|
|
29
|
+
threshold?: bigint; // Default: 100 ETH
|
|
30
|
+
betAmount?: bigint; // Default: 1 ETH per square
|
|
31
|
+
minSquares?: number; // Default: 3
|
|
32
|
+
maxSquares?: number; // Default: 5
|
|
33
|
+
checkInterval?: number; // Default: 5000ms (5 seconds)
|
|
34
|
+
} = {}
|
|
35
|
+
) {
|
|
36
|
+
this.sdk = sdk;
|
|
37
|
+
this.threshold = options.threshold ?? parseEther('100');
|
|
38
|
+
this.betAmount = options.betAmount ?? parseEther('1');
|
|
39
|
+
this.minSquares = options.minSquares ?? 3;
|
|
40
|
+
this.maxSquares = options.maxSquares ?? 5;
|
|
41
|
+
this.checkInterval = options.checkInterval ?? 5000;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Start the automated betting bot
|
|
46
|
+
*/
|
|
47
|
+
async start(): Promise<void> {
|
|
48
|
+
if (this.isRunning) {
|
|
49
|
+
console.log('Bot is already running');
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (!this.sdk.getWalletClient()) {
|
|
54
|
+
throw new Error('Wallet client required for automated betting');
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
this.isRunning = true;
|
|
58
|
+
console.log('π€ Automated betting bot started');
|
|
59
|
+
console.log(`Threshold: ${SlvrSDK.formatToken(this.threshold)} ETH`);
|
|
60
|
+
console.log(`Bet amount per square: ${SlvrSDK.formatToken(this.betAmount)} ETH`);
|
|
61
|
+
console.log(`Checking every ${this.checkInterval / 1000} seconds`);
|
|
62
|
+
|
|
63
|
+
// Check immediately
|
|
64
|
+
await this.checkAndBet();
|
|
65
|
+
|
|
66
|
+
// Then check at intervals
|
|
67
|
+
this.intervalId = setInterval(async () => {
|
|
68
|
+
await this.checkAndBet();
|
|
69
|
+
}, this.checkInterval);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Stop the automated betting bot
|
|
74
|
+
*/
|
|
75
|
+
stop(): void {
|
|
76
|
+
if (!this.isRunning) {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
this.isRunning = false;
|
|
81
|
+
if (this.intervalId) {
|
|
82
|
+
clearInterval(this.intervalId);
|
|
83
|
+
this.intervalId = undefined;
|
|
84
|
+
}
|
|
85
|
+
console.log('π Automated betting bot stopped');
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Check current round and place bet if conditions are met
|
|
90
|
+
*/
|
|
91
|
+
private async checkAndBet(): Promise<void> {
|
|
92
|
+
try {
|
|
93
|
+
const roundId = await this.sdk.lottery.currentRoundId();
|
|
94
|
+
const round = await this.sdk.lottery.getRound(roundId);
|
|
95
|
+
const isOpen = await this.sdk.lottery.roundOpen(roundId);
|
|
96
|
+
|
|
97
|
+
if (!isOpen) {
|
|
98
|
+
console.log(`βΈοΈ Round ${roundId} is not open for betting`);
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Check if total wager is below threshold
|
|
103
|
+
if (round.totalWager >= this.threshold) {
|
|
104
|
+
console.log(
|
|
105
|
+
`π° Round ${roundId} has ${SlvrSDK.formatToken(round.totalWager)} ETH ` +
|
|
106
|
+
`(above threshold of ${SlvrSDK.formatToken(this.threshold)} ETH)`
|
|
107
|
+
);
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
console.log(
|
|
112
|
+
`π― Round ${roundId} has ${SlvrSDK.formatToken(round.totalWager)} ETH ` +
|
|
113
|
+
`(below threshold of ${SlvrSDK.formatToken(this.threshold)} ETH)`
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
// Get squares with least allocation
|
|
117
|
+
const squares = await this.getLeastAllocatedSquares();
|
|
118
|
+
|
|
119
|
+
if (squares.length < this.minSquares) {
|
|
120
|
+
console.log(`β οΈ Not enough squares with low allocation (found ${squares.length}, need ${this.minSquares})`);
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Limit to maxSquares
|
|
125
|
+
const squaresToBet = squares.slice(0, this.maxSquares);
|
|
126
|
+
const amounts = squaresToBet.map(() => this.betAmount);
|
|
127
|
+
|
|
128
|
+
console.log(`π Betting on squares: ${squaresToBet.join(', ')}`);
|
|
129
|
+
console.log(`π΅ Total bet: ${SlvrSDK.formatToken(amounts.reduce((sum, amt) => sum + amt, 0n))} ETH`);
|
|
130
|
+
|
|
131
|
+
// Place the bet
|
|
132
|
+
const txHash = await this.sdk.lottery.bet({
|
|
133
|
+
roundId,
|
|
134
|
+
squares: squaresToBet,
|
|
135
|
+
amounts,
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
console.log(`β
Bet placed! Transaction: ${txHash}`);
|
|
139
|
+
} catch (error) {
|
|
140
|
+
console.error('β Error in automated betting:', error);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Get squares with the least funds allocated, sorted by total amount
|
|
146
|
+
*/
|
|
147
|
+
private async getLeastAllocatedSquares(): Promise<number[]> {
|
|
148
|
+
const roundId = await this.sdk.lottery.currentRoundId();
|
|
149
|
+
const squares = await this.sdk.lottery.getRoundSquares(roundId);
|
|
150
|
+
|
|
151
|
+
// Sort by total amount (ascending) - least allocated first
|
|
152
|
+
const sorted = squares
|
|
153
|
+
.map(({ square, total }) => ({ square, total }))
|
|
154
|
+
.sort((a, b) => {
|
|
155
|
+
if (a.total < b.total) return -1;
|
|
156
|
+
if (a.total > b.total) return 1;
|
|
157
|
+
return 0;
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
return sorted.map(({ square }) => square);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Example usage
|
|
166
|
+
*
|
|
167
|
+
* Set PRIVATE_KEY environment variable to enable betting
|
|
168
|
+
*/
|
|
169
|
+
export async function exampleAutomatedBetting() {
|
|
170
|
+
const { createPublicClient, createWalletClient, http } = await import('viem');
|
|
171
|
+
const { defineChain } = await import('viem');
|
|
172
|
+
const { privateKeyToAccount } = await import('viem/accounts');
|
|
173
|
+
const { SlvrSDK } = await import('../src');
|
|
174
|
+
const { CONTRACTS, ROBINHOOD_CHAIN } = await import('./constants');
|
|
175
|
+
|
|
176
|
+
// Create clients
|
|
177
|
+
const robinhood = defineChain(ROBINHOOD_CHAIN);
|
|
178
|
+
const publicClient = createPublicClient({
|
|
179
|
+
chain: robinhood,
|
|
180
|
+
transport: http(),
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
const privateKey = process.env.PRIVATE_KEY;
|
|
184
|
+
if (!privateKey) {
|
|
185
|
+
throw new Error('PRIVATE_KEY environment variable is required');
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const account = privateKeyToAccount(privateKey as `0x${string}`);
|
|
189
|
+
const walletClient = createWalletClient({
|
|
190
|
+
chain: robinhood,
|
|
191
|
+
transport: http(),
|
|
192
|
+
account,
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
// Initialize SDK
|
|
196
|
+
const sdk = new SlvrSDK({
|
|
197
|
+
publicClient,
|
|
198
|
+
walletClient,
|
|
199
|
+
addresses: {
|
|
200
|
+
lottery: CONTRACTS.LOTTERY,
|
|
201
|
+
staking: CONTRACTS.STAKING,
|
|
202
|
+
token: CONTRACTS.TOKEN,
|
|
203
|
+
autoCommit: CONTRACTS.AUTO_COMMIT !== '0x...' ? CONTRACTS.AUTO_COMMIT : undefined,
|
|
204
|
+
},
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
// Create bot with custom options
|
|
208
|
+
const bot = new AutomatedBettingBot(sdk, {
|
|
209
|
+
threshold: parseEther('100'), // Bet when round has less than 100 ETH
|
|
210
|
+
betAmount: parseEther('1'), // Bet 1 ETH per square
|
|
211
|
+
minSquares: 3, // Bet on at least 3 squares
|
|
212
|
+
maxSquares: 5, // Bet on at most 5 squares
|
|
213
|
+
checkInterval: 5000, // Check every 5 seconds
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
// Start the bot
|
|
217
|
+
await bot.start();
|
|
218
|
+
|
|
219
|
+
// Handle graceful shutdown
|
|
220
|
+
process.on('SIGINT', () => {
|
|
221
|
+
console.log('\nReceived SIGINT, stopping bot...');
|
|
222
|
+
bot.stop();
|
|
223
|
+
process.exit(0);
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
process.on('SIGTERM', () => {
|
|
227
|
+
console.log('\nReceived SIGTERM, stopping bot...');
|
|
228
|
+
bot.stop();
|
|
229
|
+
process.exit(0);
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
|