rain-sdk-v2 2.1.8 → 2.3.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 +82 -0
- package/README.md +112 -3
- package/dist/Rain.d.ts +28 -2
- package/dist/Rain.js +45 -3
- package/dist/api/helpers.d.ts +15 -1
- package/dist/api/helpers.js +36 -2
- package/dist/api/investments.js +7 -2
- package/dist/api/pools.d.ts +3 -3
- package/dist/api/pools.js +2 -2
- package/dist/api/types.d.ts +47 -0
- package/dist/api/whitelistedTokens.js +7 -2
- package/dist/auth/login.js +22 -2
- package/dist/auth/types.d.ts +4 -2
- package/dist/config/environments.d.ts +2 -0
- package/dist/config/environments.js +4 -0
- package/dist/index.d.ts +8 -2
- package/dist/index.js +3 -1
- package/dist/socket/RainSocket.d.ts +79 -40
- package/dist/socket/RainSocket.js +38 -0
- package/dist/tx/buildAddLiquidityRawTx.js +4 -0
- package/dist/tx/buildEnterOptionRawTx.js +4 -0
- package/dist/tx/buildPlaceOrderRawTx.js +3 -0
- package/dist/tx/buildRemoveLiquidityRawTx.js +4 -0
- package/dist/tx/buildSellOptionRawTx.js +3 -0
- package/dist/tx/execute.d.ts +30 -0
- package/dist/tx/execute.js +25 -0
- package/dist/tx/validation.d.ts +16 -0
- package/dist/tx/validation.js +45 -0
- package/dist/types.d.ts +4 -2
- package/package.json +3 -2
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to `rain-sdk-v2` are documented here. This project follows
|
|
4
|
+
[Semantic Versioning](https://semver.org/).
|
|
5
|
+
|
|
6
|
+
## Deprecation policy
|
|
7
|
+
|
|
8
|
+
APIs slated for removal are marked `@deprecated` in the type declarations for at
|
|
9
|
+
least one minor release before they are removed, with the replacement named in
|
|
10
|
+
the deprecation notice. Breaking removals land only in a major version.
|
|
11
|
+
|
|
12
|
+
## [2.3.0] - Developer experience
|
|
13
|
+
|
|
14
|
+
Additive, non-breaking. Fills in the untyped core data model and adds the
|
|
15
|
+
convenience helpers the docs previously pushed onto the caller.
|
|
16
|
+
|
|
17
|
+
### Added
|
|
18
|
+
- **Typed pool DTOs (F-05):** exported `Pool`, `SubPool`, `PaginatedPools`, and
|
|
19
|
+
`TradingModelName`. `getPublicPools` / `getPrivatePools` now return
|
|
20
|
+
`ApiResponse<PaginatedPools>` instead of `unknown`. Socket `*EventData`
|
|
21
|
+
payloads now type their `pool` / `subPool` / `subMarkets` fields as
|
|
22
|
+
`Pool` / `SubPool`. Interfaces carry an index signature, so they are a safe
|
|
23
|
+
superset of the wire (dynamic field access still works).
|
|
24
|
+
- **`rain.execute(txs, executor)` (F-07):** sequences the `[approval, main]`
|
|
25
|
+
arrays the builders return — sends each tx and awaits its receipt before the
|
|
26
|
+
next. Pluggable `TxExecutor` (`{ send, wait? }`) adapts to viem, ethers, or
|
|
27
|
+
RainAA. Also exported as the standalone `executeTxs`.
|
|
28
|
+
- **`rain.parseAmount` / `rain.formatAmount` (F-14):** convert between
|
|
29
|
+
human-readable amounts and base units using the token's configured decimals
|
|
30
|
+
(no more hand-tracking that USDT is 6 and RAIN is 18).
|
|
31
|
+
- **`RAIN_SOCKET_EVENTS` (F-16):** correctly-spelled camelCase aliases for the
|
|
32
|
+
raw wire event names (including the upstream-misspelled `dispute-time-extented`).
|
|
33
|
+
- **Token expiry (F-13):** `LoginResult.expiresAt` exposes the decoded JWT `exp`
|
|
34
|
+
(unix seconds) so apps can renew proactively.
|
|
35
|
+
|
|
36
|
+
## [2.2.0] - Guardrails
|
|
37
|
+
|
|
38
|
+
Adds fail-fast validation and structured errors. These surface mistakes
|
|
39
|
+
synchronously (before broadcast) instead of as on-chain reverts or parsed
|
|
40
|
+
strings. Existing `catch (e)` blocks keep working — the new errors extend `Error`.
|
|
41
|
+
|
|
42
|
+
### Added
|
|
43
|
+
- **Build-time parameter validation (F-03):** every transaction builder now
|
|
44
|
+
rejects the documented footguns before encoding — a `deadline` that looks like
|
|
45
|
+
a duration (`< 1_000_000_000`) or is already expired, a `slippageTolerance`
|
|
46
|
+
outside `0–100` (whole percent, not bps), and a 0-based `option`/`selectedOption`
|
|
47
|
+
(options are 1-based). Throws the new `RainValidationError`. Exported helpers:
|
|
48
|
+
`assertDeadline`, `assertSlippage`, `assertOption`.
|
|
49
|
+
- **Structured API errors (F-06):** non-2xx REST responses now throw
|
|
50
|
+
`RainApiError` carrying `status`, `endpoint`, `body`, and a stable `code`
|
|
51
|
+
(`NOT_FOUND` | `UNAUTHORIZED` | `FORBIDDEN` | `RATE_LIMITED` | `SERVER_ERROR` |
|
|
52
|
+
`UNKNOWN`) — branch on `err.code` instead of parsing message strings.
|
|
53
|
+
|
|
54
|
+
### Changed
|
|
55
|
+
- **Empty states are no longer errors (F-06):** `getPnlByPoolId` (no position)
|
|
56
|
+
and `getTokenPrice` (non-whitelisted token) now return
|
|
57
|
+
`{ statusCode: 200, data: null }` on a 404 instead of throwing.
|
|
58
|
+
- **Deterministic default RPC (F-09):** omitting `rpcUrl` now resolves to a
|
|
59
|
+
single fixed public RPC (previously random per instance). In `production`
|
|
60
|
+
without an `rpcUrl`, the SDK emits a `console.warn` recommending a dedicated
|
|
61
|
+
endpoint.
|
|
62
|
+
|
|
63
|
+
## [2.1.9] - Correctness patch
|
|
64
|
+
|
|
65
|
+
Addresses findings from the September 2026 independent technical review. No
|
|
66
|
+
behaviour change for correct callers.
|
|
67
|
+
|
|
68
|
+
### Fixed
|
|
69
|
+
- **Missing type exports (F-10):** `SellOptionTxParams`, `EntrySharesResult`,
|
|
70
|
+
`SellProceedsResult`, and `OrderLevelInfo` are now exported from the package
|
|
71
|
+
root, so consumers can annotate their own functions with them.
|
|
72
|
+
- **`RainConfig` type honesty (F-04):** `alchemyApiKey` and `paymasterPolicyId`
|
|
73
|
+
are now required in the type — the `RainAA` constructor already threw without
|
|
74
|
+
them. The type now matches runtime behaviour.
|
|
75
|
+
- **`smartWalletAddress` optional (F-08):** `LoginParams.smartWalletAddress` is
|
|
76
|
+
now optional and defaults to `walletAddress`, so plain-EOA integrations no
|
|
77
|
+
longer have to pass the address twice.
|
|
78
|
+
|
|
79
|
+
### Notes
|
|
80
|
+
- Two review findings (F-01 reverting order reads, F-02 REST type/wire
|
|
81
|
+
mismatches) require verification against the live dev API/contracts before any
|
|
82
|
+
change and are intentionally not addressed in this release.
|
package/README.md
CHANGED
|
@@ -24,7 +24,7 @@ import { arbitrum } from 'viem/chains';
|
|
|
24
24
|
// Initialize SDK
|
|
25
25
|
const rain = new Rain({
|
|
26
26
|
environment: 'development', // 'development' | 'stage' | 'production'
|
|
27
|
-
rpcUrl: 'https://arb1.arbitrum.io/rpc', // optional
|
|
27
|
+
rpcUrl: 'https://arb1.arbitrum.io/rpc', // optional; falls back to a public RPC (pass your own in production)
|
|
28
28
|
});
|
|
29
29
|
|
|
30
30
|
// Get environment config
|
|
@@ -62,7 +62,7 @@ const rain = new Rain(config?: RainCoreConfig);
|
|
|
62
62
|
| Parameter | Type | Default | Description |
|
|
63
63
|
|-----------|------|---------|-------------|
|
|
64
64
|
| `environment` | `'development' \| 'stage' \| 'production'` | `'development'` | Target environment |
|
|
65
|
-
| `rpcUrl` | `string` |
|
|
65
|
+
| `rpcUrl` | `string` | Fixed public RPC | Custom Arbitrum RPC URL. Omitting it uses a single deterministic public RPC; in `production` this also emits a `console.warn` — pass a dedicated endpoint. |
|
|
66
66
|
| `apiUrl` | `string` | From environment | Custom API URL |
|
|
67
67
|
|
|
68
68
|
---
|
|
@@ -852,7 +852,7 @@ const signature = await signLoginMessage(walletClient, '0x...' as `0x${string}`)
|
|
|
852
852
|
const result = await rain.login({
|
|
853
853
|
signature, // from signLoginMessage
|
|
854
854
|
walletAddress: '0x...', // EOA address
|
|
855
|
-
smartWalletAddress: '0x...', //
|
|
855
|
+
smartWalletAddress: '0x...', // optional — defaults to walletAddress for plain-EOA integrations
|
|
856
856
|
referredBy: 'CODE', // optional referral code
|
|
857
857
|
});
|
|
858
858
|
|
|
@@ -1544,6 +1544,115 @@ socket.disconnect();
|
|
|
1544
1544
|
|
|
1545
1545
|
---
|
|
1546
1546
|
|
|
1547
|
+
## Helpers & Execution
|
|
1548
|
+
|
|
1549
|
+
### Executing transactions
|
|
1550
|
+
|
|
1551
|
+
Builders return unsigned `RawTransaction[]` where index 0 may be an ERC-20
|
|
1552
|
+
approval. `rain.execute()` sends them in order and waits for each receipt before
|
|
1553
|
+
the next — so the main transaction never front-runs its approval:
|
|
1554
|
+
|
|
1555
|
+
```typescript
|
|
1556
|
+
const txs = await rain.buildEnterOptionTx({ /* ... */ });
|
|
1557
|
+
|
|
1558
|
+
await rain.execute(txs, {
|
|
1559
|
+
send: (tx) => walletClient.sendTransaction({ to: tx.to, data: tx.data, value: tx.value ?? 0n }),
|
|
1560
|
+
wait: (hash) => publicClient.waitForTransactionReceipt({ hash }),
|
|
1561
|
+
});
|
|
1562
|
+
```
|
|
1563
|
+
|
|
1564
|
+
The executor is pluggable — adapt `{ send, wait? }` to viem, ethers, RainAA, or
|
|
1565
|
+
your own KMS. Also available as the standalone `executeTxs(txs, executor)`.
|
|
1566
|
+
|
|
1567
|
+
### Amount conversion
|
|
1568
|
+
|
|
1569
|
+
Convert between human-readable amounts and base units using the token's
|
|
1570
|
+
configured decimals — no need to track that USDT is 6 and RAIN is 18:
|
|
1571
|
+
|
|
1572
|
+
```typescript
|
|
1573
|
+
rain.parseAmount('5', usdtAddress); // 5_000_000n
|
|
1574
|
+
rain.formatAmount(5_000_000n, usdtAddress); // '5'
|
|
1575
|
+
```
|
|
1576
|
+
|
|
1577
|
+
### Typed pool data
|
|
1578
|
+
|
|
1579
|
+
`getPublicPools` / `getPrivatePools` return `ApiResponse<PaginatedPools>`, and
|
|
1580
|
+
socket event payloads type their `pool` / `subPool` fields as `Pool` / `SubPool`.
|
|
1581
|
+
Import the DTOs to annotate your own code:
|
|
1582
|
+
|
|
1583
|
+
```typescript
|
|
1584
|
+
import type { Pool, SubPool, PaginatedPools } from 'rain-sdk-v2';
|
|
1585
|
+
```
|
|
1586
|
+
|
|
1587
|
+
### Socket event names
|
|
1588
|
+
|
|
1589
|
+
Use `RAIN_SOCKET_EVENTS` for correctly-spelled event identifiers with the
|
|
1590
|
+
low-level `.on()` API (some raw wire names are misspelled upstream):
|
|
1591
|
+
|
|
1592
|
+
```typescript
|
|
1593
|
+
import { RAIN_SOCKET_EVENTS } from 'rain-sdk-v2';
|
|
1594
|
+
socket.on(RAIN_SOCKET_EVENTS.disputeTimeExtended, poolId, handler);
|
|
1595
|
+
```
|
|
1596
|
+
|
|
1597
|
+
### Token expiry
|
|
1598
|
+
|
|
1599
|
+
`login()` returns `expiresAt` (unix seconds, decoded from the JWT) so you can
|
|
1600
|
+
renew before it lapses:
|
|
1601
|
+
|
|
1602
|
+
```typescript
|
|
1603
|
+
const { accessToken, expiresAt } = await rain.login({ /* ... */ });
|
|
1604
|
+
```
|
|
1605
|
+
|
|
1606
|
+
---
|
|
1607
|
+
|
|
1608
|
+
## Error Handling & Validation
|
|
1609
|
+
|
|
1610
|
+
### Build-time validation
|
|
1611
|
+
|
|
1612
|
+
Transaction builders validate their inputs synchronously — before any encoding
|
|
1613
|
+
or broadcast — and throw `RainValidationError` on the common footguns:
|
|
1614
|
+
|
|
1615
|
+
- `deadline` must be an **absolute unix timestamp** (seconds), not a duration.
|
|
1616
|
+
`deadline: 600n` is rejected; use `BigInt(Math.floor(Date.now()/1000) + 600)`.
|
|
1617
|
+
- `slippageTolerance` is a **whole percent** (`5n` = 5%), and must be `0–100`.
|
|
1618
|
+
- `option` / `selectedOption` are **1-based** (the first option is `1`, never `0`).
|
|
1619
|
+
|
|
1620
|
+
```typescript
|
|
1621
|
+
import { RainValidationError } from 'rain-sdk-v2';
|
|
1622
|
+
|
|
1623
|
+
try {
|
|
1624
|
+
await rain.buildEnterOptionTx({ /* ... */, deadline: 600n });
|
|
1625
|
+
} catch (err) {
|
|
1626
|
+
if (err instanceof RainValidationError) {
|
|
1627
|
+
console.error(err.field, err.message); // 'deadline', 'Invalid deadline: ...'
|
|
1628
|
+
}
|
|
1629
|
+
}
|
|
1630
|
+
```
|
|
1631
|
+
|
|
1632
|
+
### API errors
|
|
1633
|
+
|
|
1634
|
+
REST methods throw `RainApiError` (a subclass of `Error`) on non-2xx responses,
|
|
1635
|
+
carrying structured fields so you can branch on `code` instead of parsing strings:
|
|
1636
|
+
|
|
1637
|
+
```typescript
|
|
1638
|
+
import { RainApiError } from 'rain-sdk-v2';
|
|
1639
|
+
|
|
1640
|
+
try {
|
|
1641
|
+
await rain.getSomeData(/* ... */);
|
|
1642
|
+
} catch (err) {
|
|
1643
|
+
if (err instanceof RainApiError) {
|
|
1644
|
+
console.error(err.status, err.code, err.endpoint, err.body);
|
|
1645
|
+
// code: 'NOT_FOUND' | 'UNAUTHORIZED' | 'FORBIDDEN' | 'RATE_LIMITED' | 'SERVER_ERROR' | 'UNKNOWN'
|
|
1646
|
+
}
|
|
1647
|
+
}
|
|
1648
|
+
```
|
|
1649
|
+
|
|
1650
|
+
Legitimate empty states are **not** errors: `getPnlByPoolId` (no position) and
|
|
1651
|
+
`getTokenPrice` (non-whitelisted token) return `{ statusCode: 200, data: null }`
|
|
1652
|
+
rather than throwing on a 404.
|
|
1653
|
+
|
|
1654
|
+
---
|
|
1655
|
+
|
|
1547
1656
|
## License
|
|
1548
1657
|
|
|
1549
1658
|
MIT
|
package/dist/Rain.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ import { LoginParams, LoginResult } from './auth/types.js';
|
|
|
6
6
|
import { SellProceedsResult } from './markets/getSellProceeds.js';
|
|
7
7
|
import { OptionDisputeInfo, OptionAppealInfo } from './markets/getDisputeState.js';
|
|
8
8
|
import { EntrySharesResult } from './markets/getEntryShares.js';
|
|
9
|
+
import { TxExecutor } from './tx/execute.js';
|
|
9
10
|
import type { UserProfileUpdateParams, UserHistoryParams, CreateCommentParams, CommentsListingParams, UpdateCommentParams, CommentCountParams, PublicPoolsParams, PrivatePoolsParams, PoolListingByCreatorParams, VerifyAccessCodeParams, PoolTotalParticipantsParams, SearchPoolParams, RelatedPoolsParams, UpdateStreamingParams, UpdatePoolResolutionTimeParams, FindPoolFallbackParams, SignOraclesExtendTimeParams, TrendingTagsParams, UserTotalInvestmentParams, OptionsTotalVolumeParams, PoolActivityParams, TopHoldersParams, UserInvestedPoolsParams, InvestmentVolumeGraphParams, UserPnlGraphParams, TopWinnersLosersParams, PnlByPoolIdParams, UserPositionsParams, OpenPositionsParams, UserSharePositionsParams, SearchInvestedPoolsParams, PriceDataParams, AddReviewParams, GetUserOrdersParams, OrderBookParams, GetUserOrderByPoolIdParams, OrdersListingByPoolParams, AddUserPointsParams, UserOnboardingParams, PointsGraphParams, GetNotificationsParams, MarkNotificationAsReadParams, CreateDisputeMessageParams, GetPoolDisputeConvoParams, FollowToggleParams, FollowCheckParams, FollowListParams, FollowStatsParams, RainBurnPerPoolParams, ToggleBookmarkParams, GetBookmarksParams, CheckBookmarkParams, LeaderboardParams, LeaderboardSearchParams, TraderRecentTradesParams } from './api/types.js';
|
|
10
11
|
export declare class Rain {
|
|
11
12
|
readonly environment: RainEnvironment;
|
|
@@ -19,6 +20,31 @@ export declare class Rain {
|
|
|
19
20
|
*/
|
|
20
21
|
getTokenConfig(tokenAddress: `0x${string}`): import("./config/environments.js").TokenConfig | null;
|
|
21
22
|
buildApprovalTx(params: ApproveTxParams): RawTransaction;
|
|
23
|
+
/**
|
|
24
|
+
* Sequences an ordered list of raw transactions through a pluggable executor,
|
|
25
|
+
* awaiting each receipt before the next send. Use this for the `[approval, main]`
|
|
26
|
+
* arrays the builders return so the main tx never front-runs its approval.
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* const txs = await rain.buildEnterOptionTx({ ... });
|
|
30
|
+
* await rain.execute(txs, {
|
|
31
|
+
* send: (tx) => walletClient.sendTransaction({ to: tx.to, data: tx.data, value: tx.value ?? 0n }),
|
|
32
|
+
* wait: (hash) => publicClient.waitForTransactionReceipt({ hash }),
|
|
33
|
+
* });
|
|
34
|
+
*/
|
|
35
|
+
execute(txs: RawTransaction[], executor: TxExecutor): Promise<`0x${string}`[]>;
|
|
36
|
+
/**
|
|
37
|
+
* Convert a human-readable amount to base units (wei) using the token's
|
|
38
|
+
* configured decimals. Throws if the token is not in the environment config.
|
|
39
|
+
* @example rain.parseAmount('5', usdtAddress) // 5_000_000n for 6-decimal USDT
|
|
40
|
+
*/
|
|
41
|
+
parseAmount(value: string | number, tokenAddress: `0x${string}`): bigint;
|
|
42
|
+
/**
|
|
43
|
+
* Convert a base-unit (wei) amount to a human-readable string using the
|
|
44
|
+
* token's configured decimals. Throws if the token is not in the config.
|
|
45
|
+
* @example rain.formatAmount(5_000_000n, usdtAddress) // '5' for 6-decimal USDT
|
|
46
|
+
*/
|
|
47
|
+
formatAmount(amount: bigint, tokenAddress: `0x${string}`): string;
|
|
22
48
|
getCreateMarketFees(tokenAddress: `0x${string}`, inputAmountWei: bigint): Promise<{
|
|
23
49
|
oracleFeePerOption: bigint;
|
|
24
50
|
liquidityFee: bigint;
|
|
@@ -233,8 +259,8 @@ export declare class Rain {
|
|
|
233
259
|
poolId: string;
|
|
234
260
|
accessCode: string;
|
|
235
261
|
}, accessToken?: string): Promise<import("./api/types.js").ApiResponse<unknown>>;
|
|
236
|
-
getPublicPools(params: PublicPoolsParams, accessToken?: string): Promise<import("./api/types.js").ApiResponse<
|
|
237
|
-
getPrivatePools(params: PrivatePoolsParams, accessToken?: string): Promise<import("./api/types.js").ApiResponse<
|
|
262
|
+
getPublicPools(params: PublicPoolsParams, accessToken?: string): Promise<import("./api/types.js").ApiResponse<import("./api/types.js").PaginatedPools>>;
|
|
263
|
+
getPrivatePools(params: PrivatePoolsParams, accessToken?: string): Promise<import("./api/types.js").ApiResponse<import("./api/types.js").PaginatedPools>>;
|
|
238
264
|
getPoolById(params: {
|
|
239
265
|
id: string;
|
|
240
266
|
}, accessToken?: string): Promise<import("./api/types.js").ApiResponse<unknown>>;
|
package/dist/Rain.js
CHANGED
|
@@ -14,7 +14,7 @@ import { buildCancelBuyOrdersRawTx, buildCancelSellOrdersRawTx } from './tx/buil
|
|
|
14
14
|
import { buildCalculateWinnerRawTx } from './tx/buildCalculateWinnerRawTx.js';
|
|
15
15
|
import { buildExtendTimeRawTx } from './tx/buildExtendTimeRawTx.js';
|
|
16
16
|
import { getUserActiveBuyOrders, getUserActiveSellOrders, getFirstBuyOrderPrice, getFirstSellOrderPrice, getBuyOrdersAtPrice, getSellOrdersAtPrice, checkOrderExists } from './markets/getOrderInfo.js';
|
|
17
|
-
import { ALLOWED_ENVIRONMENTS, ENV_CONFIG,
|
|
17
|
+
import { ALLOWED_ENVIRONMENTS, ENV_CONFIG, getDefaultRpc } from './config/environments.js';
|
|
18
18
|
import { loginUser } from './auth/login.js';
|
|
19
19
|
import { getUserOptionLPShares } from './markets/getUserOptionLPShares.js';
|
|
20
20
|
import { getUserOptionShares } from './markets/getUserOptionShares.js';
|
|
@@ -28,7 +28,8 @@ import { getResolverBondAmount } from './markets/getResolverBondAmount.js';
|
|
|
28
28
|
import { getDisputeAppealFee } from './markets/getDisputeFee.js';
|
|
29
29
|
import { optionResolverBond, optionResolutionProposer, isOptionDisputed, isOptionAppealed, optionDispute, optionAppeal } from './markets/getDisputeState.js';
|
|
30
30
|
import { getEntryShares } from './markets/getEntryShares.js';
|
|
31
|
-
import {
|
|
31
|
+
import { executeTxs } from './tx/execute.js';
|
|
32
|
+
import { createPublicClient, http, parseAbi, parseUnits, formatUnits } from 'viem';
|
|
32
33
|
import { arbitrum } from 'viem/chains';
|
|
33
34
|
import * as usersApi from './api/users.js';
|
|
34
35
|
import * as commentsApi from './api/comments.js';
|
|
@@ -72,7 +73,11 @@ export class Rain {
|
|
|
72
73
|
throw new Error(`Invalid environment "${environment}". Allowed values: ${ALLOWED_ENVIRONMENTS.join(", ")}`);
|
|
73
74
|
}
|
|
74
75
|
this.environment = environment;
|
|
75
|
-
|
|
76
|
+
if (!rpcUrl && environment === "production") {
|
|
77
|
+
console.warn("[rain-sdk-v2] No rpcUrl provided in production; falling back to a public Arbitrum RPC. " +
|
|
78
|
+
"Public RPCs have shared rate limits and varying reliability — pass a dedicated rpcUrl.");
|
|
79
|
+
}
|
|
80
|
+
this.rpcUrl = rpcUrl ?? getDefaultRpc();
|
|
76
81
|
const envConfig = ENV_CONFIG[this.environment];
|
|
77
82
|
this.marketFactory = envConfig.market_factory_address;
|
|
78
83
|
this.apiUrl = apiUrl ?? envConfig.apiUrl;
|
|
@@ -94,6 +99,43 @@ export class Rain {
|
|
|
94
99
|
buildApprovalTx(params) {
|
|
95
100
|
return buildApproveRawTx(params);
|
|
96
101
|
}
|
|
102
|
+
/**
|
|
103
|
+
* Sequences an ordered list of raw transactions through a pluggable executor,
|
|
104
|
+
* awaiting each receipt before the next send. Use this for the `[approval, main]`
|
|
105
|
+
* arrays the builders return so the main tx never front-runs its approval.
|
|
106
|
+
*
|
|
107
|
+
* @example
|
|
108
|
+
* const txs = await rain.buildEnterOptionTx({ ... });
|
|
109
|
+
* await rain.execute(txs, {
|
|
110
|
+
* send: (tx) => walletClient.sendTransaction({ to: tx.to, data: tx.data, value: tx.value ?? 0n }),
|
|
111
|
+
* wait: (hash) => publicClient.waitForTransactionReceipt({ hash }),
|
|
112
|
+
* });
|
|
113
|
+
*/
|
|
114
|
+
async execute(txs, executor) {
|
|
115
|
+
return executeTxs(txs, executor);
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Convert a human-readable amount to base units (wei) using the token's
|
|
119
|
+
* configured decimals. Throws if the token is not in the environment config.
|
|
120
|
+
* @example rain.parseAmount('5', usdtAddress) // 5_000_000n for 6-decimal USDT
|
|
121
|
+
*/
|
|
122
|
+
parseAmount(value, tokenAddress) {
|
|
123
|
+
const cfg = this.getTokenConfig(tokenAddress);
|
|
124
|
+
if (!cfg)
|
|
125
|
+
throw new Error(`Unknown token ${tokenAddress}; not in the ${this.environment} environment config`);
|
|
126
|
+
return parseUnits(String(value), cfg.decimals);
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Convert a base-unit (wei) amount to a human-readable string using the
|
|
130
|
+
* token's configured decimals. Throws if the token is not in the config.
|
|
131
|
+
* @example rain.formatAmount(5_000_000n, usdtAddress) // '5' for 6-decimal USDT
|
|
132
|
+
*/
|
|
133
|
+
formatAmount(amount, tokenAddress) {
|
|
134
|
+
const cfg = this.getTokenConfig(tokenAddress);
|
|
135
|
+
if (!cfg)
|
|
136
|
+
throw new Error(`Unknown token ${tokenAddress}; not in the ${this.environment} environment config`);
|
|
137
|
+
return formatUnits(amount, cfg.decimals);
|
|
138
|
+
}
|
|
97
139
|
async getCreateMarketFees(tokenAddress, inputAmountWei) {
|
|
98
140
|
const pc = createPublicClient({ chain: arbitrum, transport: http(this.rpcUrl) });
|
|
99
141
|
const [oracleFeeRaw, liquidityFee, factoryBaseToken] = await Promise.all([
|
package/dist/api/helpers.d.ts
CHANGED
|
@@ -1,4 +1,18 @@
|
|
|
1
1
|
import { ApiConfig } from './types.js';
|
|
2
2
|
export declare function buildHeaders(config: ApiConfig, contentType?: string): Record<string, string>;
|
|
3
3
|
export declare function buildQuery(params: Record<string, string | number | boolean | undefined | null>): string;
|
|
4
|
-
export
|
|
4
|
+
export type RainApiErrorCode = 'NOT_FOUND' | 'UNAUTHORIZED' | 'FORBIDDEN' | 'RATE_LIMITED' | 'SERVER_ERROR' | 'UNKNOWN';
|
|
5
|
+
/**
|
|
6
|
+
* Structured error thrown by every REST wrapper on a non-2xx response.
|
|
7
|
+
* Extends `Error` (so existing `catch` blocks keep working) but adds
|
|
8
|
+
* `status`, `endpoint`, `body`, and a stable `code` to branch on instead of
|
|
9
|
+
* parsing message strings.
|
|
10
|
+
*/
|
|
11
|
+
export declare class RainApiError extends Error {
|
|
12
|
+
readonly status: number;
|
|
13
|
+
readonly body: unknown;
|
|
14
|
+
readonly endpoint?: string | undefined;
|
|
15
|
+
readonly code: RainApiErrorCode;
|
|
16
|
+
constructor(status: number, body: unknown, endpoint?: string | undefined, code?: RainApiErrorCode);
|
|
17
|
+
}
|
|
18
|
+
export declare function handleResponse<T>(res: Response, endpoint?: string): Promise<T>;
|
package/dist/api/helpers.js
CHANGED
|
@@ -17,10 +17,44 @@ export function buildQuery(params) {
|
|
|
17
17
|
return '';
|
|
18
18
|
return '?' + entries.map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(String(v))}`).join('&');
|
|
19
19
|
}
|
|
20
|
-
|
|
20
|
+
/**
|
|
21
|
+
* Structured error thrown by every REST wrapper on a non-2xx response.
|
|
22
|
+
* Extends `Error` (so existing `catch` blocks keep working) but adds
|
|
23
|
+
* `status`, `endpoint`, `body`, and a stable `code` to branch on instead of
|
|
24
|
+
* parsing message strings.
|
|
25
|
+
*/
|
|
26
|
+
export class RainApiError extends Error {
|
|
27
|
+
status;
|
|
28
|
+
body;
|
|
29
|
+
endpoint;
|
|
30
|
+
code;
|
|
31
|
+
constructor(status, body, endpoint, code = 'UNKNOWN') {
|
|
32
|
+
super(`Rain API error ${status}${endpoint ? ` on ${endpoint}` : ''}`);
|
|
33
|
+
this.status = status;
|
|
34
|
+
this.body = body;
|
|
35
|
+
this.endpoint = endpoint;
|
|
36
|
+
this.code = code;
|
|
37
|
+
this.name = 'RainApiError';
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
function codeForStatus(status) {
|
|
41
|
+
switch (status) {
|
|
42
|
+
case 401: return 'UNAUTHORIZED';
|
|
43
|
+
case 403: return 'FORBIDDEN';
|
|
44
|
+
case 404: return 'NOT_FOUND';
|
|
45
|
+
case 429: return 'RATE_LIMITED';
|
|
46
|
+
default: return status >= 500 ? 'SERVER_ERROR' : 'UNKNOWN';
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
export async function handleResponse(res, endpoint) {
|
|
21
50
|
if (!res.ok) {
|
|
22
51
|
const text = await res.text().catch(() => res.statusText);
|
|
23
|
-
|
|
52
|
+
let body = text;
|
|
53
|
+
try {
|
|
54
|
+
body = JSON.parse(text);
|
|
55
|
+
}
|
|
56
|
+
catch { /* not JSON — keep raw text */ }
|
|
57
|
+
throw new RainApiError(res.status, body, endpoint, codeForStatus(res.status));
|
|
24
58
|
}
|
|
25
59
|
return res.json();
|
|
26
60
|
}
|
package/dist/api/investments.js
CHANGED
|
@@ -91,11 +91,16 @@ export async function calculateUserPNLPerPool(config) {
|
|
|
91
91
|
return handleResponse(res);
|
|
92
92
|
}
|
|
93
93
|
export async function getPnlByPoolId(params, config) {
|
|
94
|
-
const
|
|
94
|
+
const endpoint = `/investments/pnl/${encodeURIComponent(params.poolId)}`;
|
|
95
|
+
const res = await fetch(`${config.apiUrl}${endpoint}`, {
|
|
95
96
|
method: 'GET',
|
|
96
97
|
headers: buildHeaders(config),
|
|
97
98
|
});
|
|
98
|
-
|
|
99
|
+
// No position in this pool is a legitimate empty state, not an error.
|
|
100
|
+
if (res.status === 404) {
|
|
101
|
+
return { statusCode: 200, message: 'No position for this pool', data: null };
|
|
102
|
+
}
|
|
103
|
+
return handleResponse(res, endpoint);
|
|
99
104
|
}
|
|
100
105
|
export async function getTopWinnersLosers(params, config) {
|
|
101
106
|
const qs = buildQuery({ timeFilter: params.timeFilter });
|
package/dist/api/pools.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { ApiConfig, ApiResponse, PublicPoolsParams, PrivatePoolsParams, PoolListingByCreatorParams, VerifyAccessCodeParams, PoolTotalParticipantsParams, SearchPoolParams, RelatedPoolsParams, UpdateStreamingParams, UpdatePoolResolutionTimeParams, FindPoolFallbackParams, SignOraclesExtendTimeParams, TrendingTagsParams } from './types.js';
|
|
1
|
+
import { ApiConfig, ApiResponse, PublicPoolsParams, PrivatePoolsParams, PoolListingByCreatorParams, VerifyAccessCodeParams, PoolTotalParticipantsParams, SearchPoolParams, RelatedPoolsParams, UpdateStreamingParams, UpdatePoolResolutionTimeParams, FindPoolFallbackParams, SignOraclesExtendTimeParams, TrendingTagsParams, PaginatedPools } from './types.js';
|
|
2
2
|
export declare function accessPool(params: {
|
|
3
3
|
poolId: string;
|
|
4
4
|
accessCode: string;
|
|
5
5
|
}, config: ApiConfig): Promise<ApiResponse>;
|
|
6
|
-
export declare function getPublicPools(params: PublicPoolsParams, config: ApiConfig): Promise<ApiResponse
|
|
7
|
-
export declare function getPrivatePools(params: PrivatePoolsParams, config: ApiConfig): Promise<ApiResponse
|
|
6
|
+
export declare function getPublicPools(params: PublicPoolsParams, config: ApiConfig): Promise<ApiResponse<PaginatedPools>>;
|
|
7
|
+
export declare function getPrivatePools(params: PrivatePoolsParams, config: ApiConfig): Promise<ApiResponse<PaginatedPools>>;
|
|
8
8
|
export declare function getPoolById(params: {
|
|
9
9
|
id: string;
|
|
10
10
|
}, config: ApiConfig): Promise<ApiResponse>;
|
package/dist/api/pools.js
CHANGED
|
@@ -9,7 +9,7 @@ export async function getPublicPools(params, config) {
|
|
|
9
9
|
method: 'GET',
|
|
10
10
|
headers: buildHeaders(config),
|
|
11
11
|
});
|
|
12
|
-
return handleResponse(res);
|
|
12
|
+
return handleResponse(res, '/pools/public-pools');
|
|
13
13
|
}
|
|
14
14
|
export async function getPrivatePools(params, config) {
|
|
15
15
|
const qs = buildQuery({ limit: params.limit, offset: params.offset, tag: params.tag, status: params.status });
|
|
@@ -17,7 +17,7 @@ export async function getPrivatePools(params, config) {
|
|
|
17
17
|
method: 'GET',
|
|
18
18
|
headers: buildHeaders(config),
|
|
19
19
|
});
|
|
20
|
-
return handleResponse(res);
|
|
20
|
+
return handleResponse(res, '/pools/pools-private');
|
|
21
21
|
}
|
|
22
22
|
export async function getPoolById(params, config) {
|
|
23
23
|
const res = await fetch(`${config.apiUrl}/pools/pool/${encodeURIComponent(params.id)}`, {
|
package/dist/api/types.d.ts
CHANGED
|
@@ -87,6 +87,53 @@ export interface PoolToken {
|
|
|
87
87
|
tokenLogo?: string;
|
|
88
88
|
}
|
|
89
89
|
export type PoolStatus = 'New' | 'Live' | 'Closing_Soon' | 'Pending_Finalization' | 'Waiting_for_Result' | 'Dispute_Window_Open' | 'Under_Dispute' | 'Appeal_Window_Open' | 'Under_Appeal' | 'Closed';
|
|
90
|
+
export type TradingModelName = 'AMM' | 'OrderBook';
|
|
91
|
+
/**
|
|
92
|
+
* A sub-market (option group) within a Pool. Known fields are typed; the
|
|
93
|
+
* `[key: string]: any` index signature preserves access to the long tail of
|
|
94
|
+
* server fields not yet enumerated here, so this is a safe superset — never a
|
|
95
|
+
* contradiction of the wire.
|
|
96
|
+
*/
|
|
97
|
+
export interface SubPool {
|
|
98
|
+
_id?: string;
|
|
99
|
+
subPoolIndex?: number;
|
|
100
|
+
question?: string;
|
|
101
|
+
options?: PoolOption[];
|
|
102
|
+
contractAddress?: string;
|
|
103
|
+
[key: string]: any;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* The central pool data model. Known fields are typed; the index signature keeps
|
|
107
|
+
* additional server fields accessible without a cast.
|
|
108
|
+
*/
|
|
109
|
+
export interface Pool {
|
|
110
|
+
_id: string;
|
|
111
|
+
contractAddress?: string;
|
|
112
|
+
question?: string;
|
|
113
|
+
status?: PoolStatus;
|
|
114
|
+
tradingModel?: TradingModelName;
|
|
115
|
+
token?: PoolToken;
|
|
116
|
+
tags?: string[];
|
|
117
|
+
options?: PoolOption[];
|
|
118
|
+
subPools?: SubPool[];
|
|
119
|
+
isPrivate?: boolean;
|
|
120
|
+
startDate?: string;
|
|
121
|
+
endDate?: string;
|
|
122
|
+
createdAt?: string;
|
|
123
|
+
updatedAt?: string;
|
|
124
|
+
[key: string]: any;
|
|
125
|
+
}
|
|
126
|
+
/** Paginated pool listing returned by `getPublicPools` / `getPrivatePools`. */
|
|
127
|
+
export interface PaginatedPools {
|
|
128
|
+
pools: Pool[];
|
|
129
|
+
pagination?: {
|
|
130
|
+
total: number;
|
|
131
|
+
offset: number;
|
|
132
|
+
limit: number;
|
|
133
|
+
totalPages: number;
|
|
134
|
+
};
|
|
135
|
+
[key: string]: any;
|
|
136
|
+
}
|
|
90
137
|
export interface CreatePoolParams {
|
|
91
138
|
question: string;
|
|
92
139
|
isPrivate: boolean;
|
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
import { buildHeaders, handleResponse } from './helpers.js';
|
|
2
2
|
export async function getTokenPrice(tokenAddress, config) {
|
|
3
|
-
const
|
|
3
|
+
const endpoint = '/whitelisted-tokens/get-token-price';
|
|
4
|
+
const res = await fetch(`${config.apiUrl}${endpoint}?tokenAddress=${encodeURIComponent(tokenAddress)}`, {
|
|
4
5
|
method: 'GET',
|
|
5
6
|
headers: buildHeaders(config),
|
|
6
7
|
});
|
|
7
|
-
|
|
8
|
+
// A non-whitelisted token is a legitimate empty state, not an error.
|
|
9
|
+
if (res.status === 404) {
|
|
10
|
+
return { statusCode: 200, message: 'Token not whitelisted or no price available', data: null };
|
|
11
|
+
}
|
|
12
|
+
return handleResponse(res, endpoint);
|
|
8
13
|
}
|
package/dist/auth/login.js
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
|
+
/** Decode the `exp` (unix seconds) claim from a JWT without verifying it. Cross-environment (browser + Node). */
|
|
2
|
+
function decodeJwtExp(token) {
|
|
3
|
+
try {
|
|
4
|
+
const part = token.split('.')[1];
|
|
5
|
+
if (!part)
|
|
6
|
+
return undefined;
|
|
7
|
+
const b64 = part.replace(/-/g, '+').replace(/_/g, '/');
|
|
8
|
+
const padded = b64 + '='.repeat((4 - (b64.length % 4)) % 4);
|
|
9
|
+
const json = typeof atob === 'function'
|
|
10
|
+
? atob(padded)
|
|
11
|
+
: Buffer.from(padded, 'base64').toString('binary');
|
|
12
|
+
const payload = JSON.parse(json);
|
|
13
|
+
return typeof payload?.exp === 'number' ? payload.exp : undefined;
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
return undefined;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
1
19
|
export async function loginUser(params) {
|
|
2
20
|
const { signature, walletAddress, smartWalletAddress, referredBy, apiUrl } = params;
|
|
21
|
+
// Plain-EOA integrations may omit smartWalletAddress; fall back to the EOA.
|
|
22
|
+
const resolvedSmartWalletAddress = smartWalletAddress ?? walletAddress;
|
|
3
23
|
const res = await fetch(`${apiUrl}/auth/login-or-register-with-walletAddress`, {
|
|
4
24
|
method: 'POST',
|
|
5
25
|
headers: {
|
|
@@ -9,7 +29,7 @@ export async function loginUser(params) {
|
|
|
9
29
|
body: JSON.stringify({
|
|
10
30
|
sign: signature,
|
|
11
31
|
walletAddress,
|
|
12
|
-
userSmartAddress:
|
|
32
|
+
userSmartAddress: resolvedSmartWalletAddress,
|
|
13
33
|
...(referredBy ? { referredBy } : {}),
|
|
14
34
|
}),
|
|
15
35
|
});
|
|
@@ -23,5 +43,5 @@ export async function loginUser(params) {
|
|
|
23
43
|
if (!accessToken || !userId) {
|
|
24
44
|
throw new Error('Login response missing token or user id');
|
|
25
45
|
}
|
|
26
|
-
return { accessToken, userId };
|
|
46
|
+
return { accessToken, userId, expiresAt: decodeJwtExp(accessToken) };
|
|
27
47
|
}
|
package/dist/auth/types.d.ts
CHANGED
|
@@ -3,8 +3,8 @@ export interface LoginParams {
|
|
|
3
3
|
signature: string;
|
|
4
4
|
/** EOA wallet address */
|
|
5
5
|
walletAddress: string;
|
|
6
|
-
/** Smart account / AA wallet address */
|
|
7
|
-
smartWalletAddress
|
|
6
|
+
/** Smart account / AA wallet address. Defaults to `walletAddress` for plain-EOA integrations. */
|
|
7
|
+
smartWalletAddress?: string;
|
|
8
8
|
/** Optional referral code */
|
|
9
9
|
referredBy?: string;
|
|
10
10
|
}
|
|
@@ -13,4 +13,6 @@ export interface LoginResult {
|
|
|
13
13
|
accessToken: string;
|
|
14
14
|
/** Backend user ID */
|
|
15
15
|
userId: string;
|
|
16
|
+
/** Token expiry as a unix timestamp (seconds), decoded from the JWT `exp` claim. Undefined if the token has no `exp`. */
|
|
17
|
+
expiresAt?: number;
|
|
16
18
|
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
export declare const ALLOWED_ENVIRONMENTS: readonly ["development", "stage", "production"];
|
|
2
2
|
export declare const DEFAULT_RPCS: string[];
|
|
3
3
|
export declare function getRandomRpc(): string;
|
|
4
|
+
/** Deterministic default RPC — every instance resolves to the same endpoint. */
|
|
5
|
+
export declare function getDefaultRpc(): string;
|
|
4
6
|
export declare const USDT_SYMBOL_DEV = "USDTm";
|
|
5
7
|
export interface TokenConfig {
|
|
6
8
|
address: `0x${string}`;
|
|
@@ -8,6 +8,10 @@ export function getRandomRpc() {
|
|
|
8
8
|
const index = Math.floor(Math.random() * DEFAULT_RPCS.length);
|
|
9
9
|
return DEFAULT_RPCS[index];
|
|
10
10
|
}
|
|
11
|
+
/** Deterministic default RPC — every instance resolves to the same endpoint. */
|
|
12
|
+
export function getDefaultRpc() {
|
|
13
|
+
return DEFAULT_RPCS[0];
|
|
14
|
+
}
|
|
11
15
|
export const USDT_SYMBOL_DEV = "USDTm";
|
|
12
16
|
export const ENV_CONFIG = {
|
|
13
17
|
development: {
|
package/dist/index.d.ts
CHANGED
|
@@ -2,7 +2,13 @@ export { Rain } from './Rain.js';
|
|
|
2
2
|
export { RainAA } from './RainAA.js';
|
|
3
3
|
export * from './types.js';
|
|
4
4
|
export { TradingModel, OptionSide } from './tx/types.js';
|
|
5
|
-
export type { CreateMarketTxParams, EnterOptionTxParams, AddLiquidityTxParams, RemoveLiquidityTxParams, SplitTxParams, MergeTxParams, ClosePoolAITxParams, ClosePoolManualTxParams, ChooseWinnerTxParams, PlaceBuyOrderTxParams, PlaceSellOrderTxParams, OpenDisputeTxParams, ClaimTxParams, CancelBuyOrdersTxParams, CancelSellOrdersTxParams, RawTransaction, ApproveTxParams } from './tx/types.js';
|
|
5
|
+
export type { CreateMarketTxParams, EnterOptionTxParams, AddLiquidityTxParams, RemoveLiquidityTxParams, SplitTxParams, MergeTxParams, ClosePoolAITxParams, ClosePoolManualTxParams, ChooseWinnerTxParams, PlaceBuyOrderTxParams, PlaceSellOrderTxParams, OpenDisputeTxParams, ClaimTxParams, CancelBuyOrdersTxParams, CancelSellOrdersTxParams, RawTransaction, ApproveTxParams, SellOptionTxParams } from './tx/types.js';
|
|
6
|
+
export type { EntrySharesResult } from './markets/getEntryShares.js';
|
|
7
|
+
export type { SellProceedsResult } from './markets/getSellProceeds.js';
|
|
8
|
+
export type { OrderLevelInfo } from './markets/getOrderInfo.js';
|
|
9
|
+
export { RainValidationError, assertDeadline, assertSlippage, assertOption } from './tx/validation.js';
|
|
10
|
+
export { executeTxs } from './tx/execute.js';
|
|
11
|
+
export type { TxExecutor } from './tx/execute.js';
|
|
6
12
|
export type { LoginParams, LoginResult } from './auth/types.js';
|
|
7
13
|
export { signLoginMessage } from './auth/signMessage.js';
|
|
8
14
|
export type { ExtendTimeTxParams } from './tx/buildExtendTimeRawTx.js';
|
|
@@ -11,5 +17,5 @@ export type { TokenConfig } from './config/environments.js';
|
|
|
11
17
|
export type { OptionDisputeInfo, OptionAppealInfo } from './markets/getDisputeState.js';
|
|
12
18
|
export { USDRAbi } from './abi/USDRAbi.js';
|
|
13
19
|
export * from './api/index.js';
|
|
14
|
-
export { RainSocket } from './socket/RainSocket.js';
|
|
20
|
+
export { RainSocket, RAIN_SOCKET_EVENTS } from './socket/RainSocket.js';
|
|
15
21
|
export type { RainSocketEvent, EnterOptionEventData, ExitOptionEventData, LiquidityEventData, SplitEventData, MergeEventData, RemoveLiquidityEventData, SyncPriceEventData, OrderCreatedEventData, OrderCancelledEventData, OrderFilledEventData, PoolClosedEventData, PoolEventData, WinnerEventData, DisputeOpenedEventData, OracleCreatedEventData, AppealOpenedEventData, DisputeWinnerEventData, AppealWinnerEventData, ClaimRewardEventData, DisputeRefundEventData } from './socket/RainSocket.js';
|
package/dist/index.js
CHANGED
|
@@ -2,7 +2,9 @@ export { Rain } from './Rain.js';
|
|
|
2
2
|
export { RainAA } from './RainAA.js';
|
|
3
3
|
export * from './types.js';
|
|
4
4
|
export { TradingModel, OptionSide } from './tx/types.js';
|
|
5
|
+
export { RainValidationError, assertDeadline, assertSlippage, assertOption } from './tx/validation.js';
|
|
6
|
+
export { executeTxs } from './tx/execute.js';
|
|
5
7
|
export { signLoginMessage } from './auth/signMessage.js';
|
|
6
8
|
export { USDRAbi } from './abi/USDRAbi.js';
|
|
7
9
|
export * from './api/index.js';
|
|
8
|
-
export { RainSocket } from './socket/RainSocket.js';
|
|
10
|
+
export { RainSocket, RAIN_SOCKET_EVENTS } from './socket/RainSocket.js';
|
|
@@ -1,33 +1,72 @@
|
|
|
1
|
+
import type { Pool, SubPool } from '../api/types.js';
|
|
1
2
|
export type RainSocketEvent = 'enter-option' | 'exit-option' | 'liquidity' | 'split' | 'merge' | 'remove-liquidity' | 'sync-price' | 'order-created' | 'order-cancelled' | 'order-filled' | 'pool-closed' | 'pool-reverted' | 'pool-token-set' | 'streamingStatusChanged' | 'winner' | 'winner-proposer' | 'reveal-winner-available' | 'dispute-opened' | 'oracle-created' | 'dispute-time-extented' | 'appeal-opened' | 'appeal-winner-calculated' | 'dispute-winner' | 'appeal-winner' | 'claim-reward' | 'dispute-refund' | 'appeal-refund' | 'resolution-refund' | 'resolver-reward' | 'notifications' | 'pool';
|
|
3
|
+
/**
|
|
4
|
+
* Correctly-spelled, camelCase aliases for the raw wire event names — use these
|
|
5
|
+
* with the low-level `.on()` API instead of hand-typing the wire strings (some
|
|
6
|
+
* of which are misspelled upstream, e.g. `dispute-time-extented`).
|
|
7
|
+
*/
|
|
8
|
+
export declare const RAIN_SOCKET_EVENTS: {
|
|
9
|
+
readonly enterOption: "enter-option";
|
|
10
|
+
readonly exitOption: "exit-option";
|
|
11
|
+
readonly liquidity: "liquidity";
|
|
12
|
+
readonly split: "split";
|
|
13
|
+
readonly merge: "merge";
|
|
14
|
+
readonly removeLiquidity: "remove-liquidity";
|
|
15
|
+
readonly syncPrice: "sync-price";
|
|
16
|
+
readonly orderCreated: "order-created";
|
|
17
|
+
readonly orderCancelled: "order-cancelled";
|
|
18
|
+
readonly orderFilled: "order-filled";
|
|
19
|
+
readonly poolClosed: "pool-closed";
|
|
20
|
+
readonly poolReverted: "pool-reverted";
|
|
21
|
+
readonly poolTokenSet: "pool-token-set";
|
|
22
|
+
readonly streamingStatusChanged: "streamingStatusChanged";
|
|
23
|
+
readonly winner: "winner";
|
|
24
|
+
readonly winnerProposer: "winner-proposer";
|
|
25
|
+
readonly revealWinnerAvailable: "reveal-winner-available";
|
|
26
|
+
readonly disputeOpened: "dispute-opened";
|
|
27
|
+
readonly oracleCreated: "oracle-created";
|
|
28
|
+
readonly disputeTimeExtended: "dispute-time-extented";
|
|
29
|
+
readonly appealOpened: "appeal-opened";
|
|
30
|
+
readonly appealWinnerCalculated: "appeal-winner-calculated";
|
|
31
|
+
readonly disputeWinner: "dispute-winner";
|
|
32
|
+
readonly appealWinner: "appeal-winner";
|
|
33
|
+
readonly claimReward: "claim-reward";
|
|
34
|
+
readonly disputeRefund: "dispute-refund";
|
|
35
|
+
readonly appealRefund: "appeal-refund";
|
|
36
|
+
readonly resolutionRefund: "resolution-refund";
|
|
37
|
+
readonly resolverReward: "resolver-reward";
|
|
38
|
+
readonly notifications: "notifications";
|
|
39
|
+
readonly pool: "pool";
|
|
40
|
+
};
|
|
2
41
|
export interface EnterOptionEventData {
|
|
3
42
|
enterOption: Record<string, any>;
|
|
4
|
-
pool:
|
|
5
|
-
subPool:
|
|
43
|
+
pool: Pool;
|
|
44
|
+
subPool: SubPool;
|
|
6
45
|
}
|
|
7
46
|
export interface ExitOptionEventData {
|
|
8
47
|
exitOption: Record<string, any>;
|
|
9
|
-
pool:
|
|
10
|
-
subPool:
|
|
48
|
+
pool: Pool;
|
|
49
|
+
subPool: SubPool;
|
|
11
50
|
}
|
|
12
51
|
export interface LiquidityEventData {
|
|
13
52
|
enterLiquidity: Record<string, any>;
|
|
14
|
-
pool:
|
|
15
|
-
subPool:
|
|
53
|
+
pool: Pool;
|
|
54
|
+
subPool: SubPool;
|
|
16
55
|
}
|
|
17
56
|
export interface SplitEventData {
|
|
18
57
|
split: Record<string, any>;
|
|
19
|
-
pool:
|
|
20
|
-
subPool:
|
|
58
|
+
pool: Pool;
|
|
59
|
+
subPool: SubPool;
|
|
21
60
|
}
|
|
22
61
|
export interface MergeEventData {
|
|
23
62
|
merge: Record<string, any>;
|
|
24
|
-
pool:
|
|
25
|
-
subPool:
|
|
63
|
+
pool: Pool;
|
|
64
|
+
subPool: SubPool;
|
|
26
65
|
}
|
|
27
66
|
export interface RemoveLiquidityEventData {
|
|
28
67
|
removeLiquidity: Record<string, any>;
|
|
29
|
-
pool:
|
|
30
|
-
subPool:
|
|
68
|
+
pool: Pool;
|
|
69
|
+
subPool: SubPool;
|
|
31
70
|
}
|
|
32
71
|
export interface SyncPriceEventData {
|
|
33
72
|
prices: Array<{
|
|
@@ -36,67 +75,67 @@ export interface SyncPriceEventData {
|
|
|
36
75
|
percentage: number;
|
|
37
76
|
subPoolIndex: number;
|
|
38
77
|
}>;
|
|
39
|
-
pool:
|
|
40
|
-
subPool:
|
|
78
|
+
pool: Pool;
|
|
79
|
+
subPool: SubPool;
|
|
41
80
|
}
|
|
42
81
|
export interface OrderCreatedEventData {
|
|
43
82
|
order: Record<string, any>;
|
|
44
|
-
pool:
|
|
45
|
-
subPool:
|
|
83
|
+
pool: Pool;
|
|
84
|
+
subPool: SubPool;
|
|
46
85
|
}
|
|
47
86
|
export interface OrderCancelledEventData {
|
|
48
87
|
order: Record<string, any>;
|
|
49
|
-
pool:
|
|
50
|
-
subPool:
|
|
88
|
+
pool: Pool;
|
|
89
|
+
subPool: SubPool;
|
|
51
90
|
}
|
|
52
91
|
export interface OrderFilledEventData {
|
|
53
92
|
filledOrder: Record<string, any>;
|
|
54
93
|
pendingOrder?: Record<string, any>;
|
|
55
|
-
pool:
|
|
56
|
-
subPool:
|
|
94
|
+
pool: Pool;
|
|
95
|
+
subPool: SubPool;
|
|
57
96
|
}
|
|
58
97
|
export interface PoolClosedEventData {
|
|
59
|
-
pool:
|
|
60
|
-
subPool?:
|
|
98
|
+
pool: Pool;
|
|
99
|
+
subPool?: SubPool;
|
|
61
100
|
}
|
|
62
101
|
export interface PoolEventData {
|
|
63
|
-
pool:
|
|
64
|
-
subMarkets?:
|
|
102
|
+
pool: Pool;
|
|
103
|
+
subMarkets?: SubPool[];
|
|
65
104
|
}
|
|
66
105
|
export interface WinnerEventData {
|
|
67
|
-
pool:
|
|
68
|
-
subPool:
|
|
106
|
+
pool: Pool;
|
|
107
|
+
subPool: SubPool;
|
|
69
108
|
}
|
|
70
109
|
export interface DisputeOpenedEventData {
|
|
71
|
-
subPool:
|
|
110
|
+
subPool: SubPool;
|
|
72
111
|
eventType: string;
|
|
73
112
|
}
|
|
74
113
|
export interface OracleCreatedEventData {
|
|
75
|
-
pool:
|
|
76
|
-
subPool:
|
|
114
|
+
pool: Pool;
|
|
115
|
+
subPool: SubPool;
|
|
77
116
|
}
|
|
78
117
|
export interface AppealOpenedEventData {
|
|
79
|
-
pool:
|
|
80
|
-
subPool:
|
|
118
|
+
pool: Pool;
|
|
119
|
+
subPool: SubPool;
|
|
81
120
|
}
|
|
82
121
|
export interface DisputeWinnerEventData {
|
|
83
|
-
subPool:
|
|
122
|
+
subPool: SubPool;
|
|
84
123
|
eventType: string;
|
|
85
124
|
}
|
|
86
125
|
export interface AppealWinnerEventData {
|
|
87
|
-
subPool:
|
|
126
|
+
subPool: SubPool;
|
|
88
127
|
eventType: string;
|
|
89
128
|
winnerFinalized: boolean;
|
|
90
129
|
}
|
|
91
130
|
export interface ClaimRewardEventData {
|
|
92
131
|
claimReward: Record<string, any>;
|
|
93
|
-
pool:
|
|
94
|
-
subPool:
|
|
132
|
+
pool: Pool;
|
|
133
|
+
subPool: SubPool;
|
|
95
134
|
}
|
|
96
135
|
export interface DisputeRefundEventData {
|
|
97
136
|
claimReward: Record<string, any>;
|
|
98
|
-
pool:
|
|
99
|
-
subPool:
|
|
137
|
+
pool: Pool;
|
|
138
|
+
subPool: SubPool;
|
|
100
139
|
}
|
|
101
140
|
export declare class RainSocket {
|
|
102
141
|
private socket;
|
|
@@ -153,12 +192,12 @@ export declare class RainSocket {
|
|
|
153
192
|
onDisputeOpened(poolId: string, callback: (data: DisputeOpenedEventData) => void): () => void;
|
|
154
193
|
onOracleCreated(poolId: string, callback: (data: OracleCreatedEventData) => void): () => void;
|
|
155
194
|
onDisputeTimeExtended(poolId: string, callback: (data: {
|
|
156
|
-
pool:
|
|
157
|
-
subPool:
|
|
195
|
+
pool: Pool;
|
|
196
|
+
subPool: SubPool;
|
|
158
197
|
}) => void): () => void;
|
|
159
198
|
onAppealOpened(poolId: string, callback: (data: AppealOpenedEventData) => void): () => void;
|
|
160
199
|
onAppealWinnerCalculated(poolId: string, callback: (data: {
|
|
161
|
-
subPool:
|
|
200
|
+
subPool: SubPool;
|
|
162
201
|
}) => void): () => void;
|
|
163
202
|
onDisputeWinner(poolId: string, callback: (data: DisputeWinnerEventData) => void): () => void;
|
|
164
203
|
onAppealWinner(poolId: string, callback: (data: AppealWinnerEventData) => void): () => void;
|
|
@@ -1,4 +1,42 @@
|
|
|
1
1
|
import { io } from 'socket.io-client';
|
|
2
|
+
/**
|
|
3
|
+
* Correctly-spelled, camelCase aliases for the raw wire event names — use these
|
|
4
|
+
* with the low-level `.on()` API instead of hand-typing the wire strings (some
|
|
5
|
+
* of which are misspelled upstream, e.g. `dispute-time-extented`).
|
|
6
|
+
*/
|
|
7
|
+
export const RAIN_SOCKET_EVENTS = {
|
|
8
|
+
enterOption: 'enter-option',
|
|
9
|
+
exitOption: 'exit-option',
|
|
10
|
+
liquidity: 'liquidity',
|
|
11
|
+
split: 'split',
|
|
12
|
+
merge: 'merge',
|
|
13
|
+
removeLiquidity: 'remove-liquidity',
|
|
14
|
+
syncPrice: 'sync-price',
|
|
15
|
+
orderCreated: 'order-created',
|
|
16
|
+
orderCancelled: 'order-cancelled',
|
|
17
|
+
orderFilled: 'order-filled',
|
|
18
|
+
poolClosed: 'pool-closed',
|
|
19
|
+
poolReverted: 'pool-reverted',
|
|
20
|
+
poolTokenSet: 'pool-token-set',
|
|
21
|
+
streamingStatusChanged: 'streamingStatusChanged',
|
|
22
|
+
winner: 'winner',
|
|
23
|
+
winnerProposer: 'winner-proposer',
|
|
24
|
+
revealWinnerAvailable: 'reveal-winner-available',
|
|
25
|
+
disputeOpened: 'dispute-opened',
|
|
26
|
+
oracleCreated: 'oracle-created',
|
|
27
|
+
disputeTimeExtended: 'dispute-time-extented',
|
|
28
|
+
appealOpened: 'appeal-opened',
|
|
29
|
+
appealWinnerCalculated: 'appeal-winner-calculated',
|
|
30
|
+
disputeWinner: 'dispute-winner',
|
|
31
|
+
appealWinner: 'appeal-winner',
|
|
32
|
+
claimReward: 'claim-reward',
|
|
33
|
+
disputeRefund: 'dispute-refund',
|
|
34
|
+
appealRefund: 'appeal-refund',
|
|
35
|
+
resolutionRefund: 'resolution-refund',
|
|
36
|
+
resolverReward: 'resolver-reward',
|
|
37
|
+
notifications: 'notifications',
|
|
38
|
+
pool: 'pool',
|
|
39
|
+
};
|
|
2
40
|
export class RainSocket {
|
|
3
41
|
socket = null;
|
|
4
42
|
url;
|
|
@@ -4,6 +4,7 @@ import { MarketsAbi } from "../abi/MarketsAbi.js";
|
|
|
4
4
|
import { ENTER_LIQUIDITY } from "../constants/contractmethods.js";
|
|
5
5
|
import { checkMarketTokenAllowance } from "../utils/helpers.js";
|
|
6
6
|
import { buildApproveRawTx } from "./buildApprovalRawTx.js";
|
|
7
|
+
import { assertOption, assertSlippage, assertDeadline } from "./validation.js";
|
|
7
8
|
const DEFAULT_SLIPPAGE = 5n; // 5%
|
|
8
9
|
const DEFAULT_DEADLINE_DURATION = 600; // 10 minutes
|
|
9
10
|
export async function buildAddLiquidityRawTx(params) {
|
|
@@ -16,6 +17,9 @@ export async function buildAddLiquidityRawTx(params) {
|
|
|
16
17
|
throw new Error("totalAmountInWei is required");
|
|
17
18
|
if (totalAmountInWei <= 0n)
|
|
18
19
|
throw new Error("totalAmountInWei must be greater than 0");
|
|
20
|
+
assertOption(option);
|
|
21
|
+
assertSlippage(slippageTolerance);
|
|
22
|
+
assertDeadline(deadline);
|
|
19
23
|
const { allowance, baseToken } = await checkMarketTokenAllowance({ marketContractAddress, owner: walletAddress, rpcUrl });
|
|
20
24
|
const txs = [];
|
|
21
25
|
if (allowance < totalAmountInWei) {
|
|
@@ -4,6 +4,7 @@ import { MarketsAbi } from "../abi/MarketsAbi.js";
|
|
|
4
4
|
import { ENTER_OPTION } from "../constants/contractmethods.js";
|
|
5
5
|
import { checkMarketTokenAllowance } from "../utils/helpers.js";
|
|
6
6
|
import { buildApproveRawTx } from "./buildApprovalRawTx.js";
|
|
7
|
+
import { assertOption, assertSlippage, assertDeadline } from "./validation.js";
|
|
7
8
|
const DEFAULT_SLIPPAGE = 5n; // 5%
|
|
8
9
|
const DEFAULT_DEADLINE_DURATION = 600; // 10 minutes
|
|
9
10
|
export async function buildEnterOptionRawTx(params) {
|
|
@@ -18,6 +19,9 @@ export async function buildEnterOptionRawTx(params) {
|
|
|
18
19
|
throw new Error("buyAmountInWei is required");
|
|
19
20
|
if (buyAmountInWei <= 0n)
|
|
20
21
|
throw new Error("buyAmountInWei must be greater than 0");
|
|
22
|
+
assertOption(selectedOption, "selectedOption");
|
|
23
|
+
assertSlippage(slippageTolerance);
|
|
24
|
+
assertDeadline(deadline);
|
|
21
25
|
const { allowance, baseToken } = await checkMarketTokenAllowance({ marketContractAddress, owner: walletAddress, rpcUrl });
|
|
22
26
|
const txs = [];
|
|
23
27
|
if (allowance < buyAmountInWei) {
|
|
@@ -3,6 +3,7 @@ import { MarketsAbi } from "../abi/MarketsAbi.js";
|
|
|
3
3
|
import { PLACE_BUY_ORDER, PLACE_SELL_ORDER } from "../constants/contractmethods.js";
|
|
4
4
|
import { checkMarketTokenAllowance } from "../utils/helpers.js";
|
|
5
5
|
import { buildApproveRawTx } from "./buildApprovalRawTx.js";
|
|
6
|
+
import { assertOption } from "./validation.js";
|
|
6
7
|
export async function buildPlaceBuyOrderRawTx(params) {
|
|
7
8
|
const { marketContractAddress, option, optionSide, price, amount, postOnly = false, walletAddress, rpcUrl } = params;
|
|
8
9
|
if (!marketContractAddress)
|
|
@@ -15,6 +16,7 @@ export async function buildPlaceBuyOrderRawTx(params) {
|
|
|
15
16
|
throw new Error("price must be greater than 0");
|
|
16
17
|
if (!amount || amount <= 0n)
|
|
17
18
|
throw new Error("amount must be greater than 0");
|
|
19
|
+
assertOption(option);
|
|
18
20
|
const { allowance, baseToken } = await checkMarketTokenAllowance({ marketContractAddress, owner: walletAddress, rpcUrl });
|
|
19
21
|
const txs = [];
|
|
20
22
|
if (allowance < amount) {
|
|
@@ -43,6 +45,7 @@ export function buildPlaceSellOrderRawTx(params) {
|
|
|
43
45
|
throw new Error("price must be greater than 0");
|
|
44
46
|
if (!shares || shares <= 0n)
|
|
45
47
|
throw new Error("shares must be greater than 0");
|
|
48
|
+
assertOption(option);
|
|
46
49
|
return {
|
|
47
50
|
to: marketContractAddress,
|
|
48
51
|
data: encodeFunctionData({
|
|
@@ -2,6 +2,7 @@ import { encodeFunctionData, createPublicClient, http } from "viem";
|
|
|
2
2
|
import { arbitrum } from "viem/chains";
|
|
3
3
|
import { MarketsAbi } from "../abi/MarketsAbi.js";
|
|
4
4
|
import { REMOVE_LIQUIDITY } from "../constants/contractmethods.js";
|
|
5
|
+
import { assertOption, assertSlippage, assertDeadline } from "./validation.js";
|
|
5
6
|
const DEFAULT_SLIPPAGE = 5n; // 5%
|
|
6
7
|
const DEFAULT_DEADLINE_DURATION = 600; // 10 minutes
|
|
7
8
|
export async function buildRemoveLiquidityRawTx(params) {
|
|
@@ -14,6 +15,9 @@ export async function buildRemoveLiquidityRawTx(params) {
|
|
|
14
15
|
throw new Error("lpShares is required");
|
|
15
16
|
if (lpShares <= 0n)
|
|
16
17
|
throw new Error("lpShares must be greater than 0");
|
|
18
|
+
assertOption(option);
|
|
19
|
+
assertSlippage(slippageTolerance);
|
|
20
|
+
assertDeadline(deadline);
|
|
17
21
|
let effectiveMinYes = minYesOut;
|
|
18
22
|
let effectiveMinNo = minNoOut;
|
|
19
23
|
if ((effectiveMinYes === undefined || effectiveMinYes === null) && (effectiveMinNo === undefined || effectiveMinNo === null)) {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { encodeFunctionData } from "viem";
|
|
2
2
|
import { MarketsAbi } from "../abi/MarketsAbi.js";
|
|
3
3
|
import { SELL_OPTION } from "../constants/contractmethods.js";
|
|
4
|
+
import { assertOption, assertDeadline } from "./validation.js";
|
|
4
5
|
const DEFAULT_DEADLINE_DURATION = 600; // 10 minutes
|
|
5
6
|
export function buildSellOptionRawTx(params) {
|
|
6
7
|
const { marketContractAddress, selectedOption, optionSide, sharesAmount, minAmountOut, deadline } = params;
|
|
@@ -15,6 +16,8 @@ export function buildSellOptionRawTx(params) {
|
|
|
15
16
|
throw new Error("sharesAmount is required");
|
|
16
17
|
if (sharesAmount <= 0n)
|
|
17
18
|
throw new Error("sharesAmount must be greater than 0");
|
|
19
|
+
assertOption(selectedOption, "selectedOption");
|
|
20
|
+
assertDeadline(deadline);
|
|
18
21
|
return {
|
|
19
22
|
to: marketContractAddress,
|
|
20
23
|
data: encodeFunctionData({
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { RawTransaction } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Pluggable executor for sending the raw transactions the builders produce.
|
|
4
|
+
* Adapt it to viem, ethers, RainAA, or your own KMS — the SDK stays key-agnostic.
|
|
5
|
+
*
|
|
6
|
+
* @example viem
|
|
7
|
+
* const executor = {
|
|
8
|
+
* send: (tx) => walletClient.sendTransaction({ to: tx.to, data: tx.data, value: tx.value ?? 0n }),
|
|
9
|
+
* wait: (hash) => publicClient.waitForTransactionReceipt({ hash }),
|
|
10
|
+
* };
|
|
11
|
+
*
|
|
12
|
+
* @example RainAA (session key)
|
|
13
|
+
* const executor = { send: (tx) => rainAA.sendTransaction(tx) };
|
|
14
|
+
*/
|
|
15
|
+
export interface TxExecutor {
|
|
16
|
+
/** Broadcast one transaction and resolve with its hash. */
|
|
17
|
+
send: (tx: RawTransaction) => Promise<`0x${string}`>;
|
|
18
|
+
/** Optional: wait for a hash to be mined before the next send. Strongly recommended for approval→main sequences. */
|
|
19
|
+
wait?: (hash: `0x${string}`) => Promise<unknown>;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Sequences an ordered list of raw transactions through an executor, awaiting
|
|
23
|
+
* each receipt (when `wait` is provided) before sending the next. This is the
|
|
24
|
+
* correct way to handle the `[approval, main]` arrays the builders return —
|
|
25
|
+
* sending the main tx before the approval lands is the most common integration
|
|
26
|
+
* bug.
|
|
27
|
+
*
|
|
28
|
+
* @returns the transaction hashes, in order.
|
|
29
|
+
*/
|
|
30
|
+
export declare function executeTxs(txs: RawTransaction[], executor: TxExecutor): Promise<`0x${string}`[]>;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sequences an ordered list of raw transactions through an executor, awaiting
|
|
3
|
+
* each receipt (when `wait` is provided) before sending the next. This is the
|
|
4
|
+
* correct way to handle the `[approval, main]` arrays the builders return —
|
|
5
|
+
* sending the main tx before the approval lands is the most common integration
|
|
6
|
+
* bug.
|
|
7
|
+
*
|
|
8
|
+
* @returns the transaction hashes, in order.
|
|
9
|
+
*/
|
|
10
|
+
export async function executeTxs(txs, executor) {
|
|
11
|
+
if (!txs || txs.length === 0)
|
|
12
|
+
return [];
|
|
13
|
+
if (typeof executor?.send !== 'function') {
|
|
14
|
+
throw new Error("executor.send is required");
|
|
15
|
+
}
|
|
16
|
+
const hashes = [];
|
|
17
|
+
for (const tx of txs) {
|
|
18
|
+
const hash = await executor.send(tx);
|
|
19
|
+
hashes.push(hash);
|
|
20
|
+
if (executor.wait) {
|
|
21
|
+
await executor.wait(hash);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return hashes;
|
|
25
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Synchronous, build-time parameter guards shared across the transaction
|
|
3
|
+
* builders. These convert documented footguns (durations passed as deadlines,
|
|
4
|
+
* slippage in the wrong unit, 0-based option indices) into immediate, descriptive
|
|
5
|
+
* errors — before any encoding or broadcast.
|
|
6
|
+
*/
|
|
7
|
+
export declare class RainValidationError extends Error {
|
|
8
|
+
readonly field: string;
|
|
9
|
+
constructor(field: string, message: string);
|
|
10
|
+
}
|
|
11
|
+
/** Deadlines are absolute unix timestamps (seconds), not durations. Optional — skipped when omitted. */
|
|
12
|
+
export declare function assertDeadline(deadline?: bigint | null): void;
|
|
13
|
+
/** slippageTolerance is a whole percent (e.g. 5 = 5%), not basis points. Optional — skipped when omitted. */
|
|
14
|
+
export declare function assertSlippage(slippageTolerance?: bigint | null): void;
|
|
15
|
+
/** Option indices are 1-based across the SDK (the first option is 1, never 0). */
|
|
16
|
+
export declare function assertOption(option: bigint | undefined | null, field?: string): void;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Synchronous, build-time parameter guards shared across the transaction
|
|
3
|
+
* builders. These convert documented footguns (durations passed as deadlines,
|
|
4
|
+
* slippage in the wrong unit, 0-based option indices) into immediate, descriptive
|
|
5
|
+
* errors — before any encoding or broadcast.
|
|
6
|
+
*/
|
|
7
|
+
export class RainValidationError extends Error {
|
|
8
|
+
field;
|
|
9
|
+
constructor(field, message) {
|
|
10
|
+
super(`Invalid ${field}: ${message}`);
|
|
11
|
+
this.field = field;
|
|
12
|
+
this.name = 'RainValidationError';
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
// Any value below this looks like a duration (seconds) rather than an absolute
|
|
16
|
+
// unix timestamp. 1_000_000_000 = 2001-09-09; any real deadline is far larger.
|
|
17
|
+
const MIN_PLAUSIBLE_TIMESTAMP = 1000000000n;
|
|
18
|
+
/** Deadlines are absolute unix timestamps (seconds), not durations. Optional — skipped when omitted. */
|
|
19
|
+
export function assertDeadline(deadline) {
|
|
20
|
+
if (deadline === undefined || deadline === null)
|
|
21
|
+
return;
|
|
22
|
+
if (deadline < MIN_PLAUSIBLE_TIMESTAMP) {
|
|
23
|
+
throw new RainValidationError('deadline', `${deadline} looks like a duration; pass an absolute unix timestamp in seconds`);
|
|
24
|
+
}
|
|
25
|
+
const now = BigInt(Math.floor(Date.now() / 1000));
|
|
26
|
+
if (deadline <= now) {
|
|
27
|
+
throw new RainValidationError('deadline', `${deadline} is already in the past`);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/** slippageTolerance is a whole percent (e.g. 5 = 5%), not basis points. Optional — skipped when omitted. */
|
|
31
|
+
export function assertSlippage(slippageTolerance) {
|
|
32
|
+
if (slippageTolerance === undefined || slippageTolerance === null)
|
|
33
|
+
return;
|
|
34
|
+
if (slippageTolerance < 0n || slippageTolerance > 100n) {
|
|
35
|
+
throw new RainValidationError('slippageTolerance', `${slippageTolerance} must be between 0 and 100 (whole percent, not basis points)`);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/** Option indices are 1-based across the SDK (the first option is 1, never 0). */
|
|
39
|
+
export function assertOption(option, field = 'option') {
|
|
40
|
+
if (option === undefined || option === null)
|
|
41
|
+
return;
|
|
42
|
+
if (option < 1n) {
|
|
43
|
+
throw new RainValidationError(field, `${option} is invalid; options are 1-based (the first option is 1)`);
|
|
44
|
+
}
|
|
45
|
+
}
|
package/dist/types.d.ts
CHANGED
|
@@ -2,8 +2,10 @@ import { WalletClient } from 'viem';
|
|
|
2
2
|
import { Chain } from 'viem/chains';
|
|
3
3
|
export interface RainConfig {
|
|
4
4
|
walletClient: WalletClient;
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
/** Required: the RainAA constructor throws without it (gas-sponsored AA). */
|
|
6
|
+
alchemyApiKey: string;
|
|
7
|
+
/** Required: the RainAA constructor throws without it (paymaster policy). */
|
|
8
|
+
paymasterPolicyId: string;
|
|
7
9
|
chain: Chain;
|
|
8
10
|
rpcUrl?: string;
|
|
9
11
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rain-sdk-v2",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.3.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Rain SDK V2 — TypeScript SDK for Rain prediction markets on Arbitrum. Market creation, trading, liquidity, order book, split/merge, dispute, and smart account support.",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -13,7 +13,8 @@
|
|
|
13
13
|
},
|
|
14
14
|
"files": [
|
|
15
15
|
"dist",
|
|
16
|
-
"README.md"
|
|
16
|
+
"README.md",
|
|
17
|
+
"CHANGELOG.md"
|
|
17
18
|
],
|
|
18
19
|
"scripts": {
|
|
19
20
|
"build": "tsc",
|