rain-sdk-v2 1.0.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/README.md +1074 -0
- package/dist/Rain.d.ts +212 -0
- package/dist/Rain.js +401 -0
- package/dist/RainAA.d.ts +62 -0
- package/dist/RainAA.js +304 -0
- package/dist/abi/CreateMarketAbi.d.ts +1125 -0
- package/dist/abi/CreateMarketAbi.js +1 -0
- package/dist/abi/ERC20Abi.d.ts +89 -0
- package/dist/abi/ERC20Abi.js +119 -0
- package/dist/abi/MarketsAbi.d.ts +2810 -0
- package/dist/abi/MarketsAbi.js +1 -0
- package/dist/abi/OracleAbi.d.ts +11 -0
- package/dist/abi/OracleAbi.js +15 -0
- package/dist/api/comments.d.ts +14 -0
- package/dist/api/comments.js +48 -0
- package/dist/api/dispute.d.ts +3 -0
- package/dist/api/dispute.js +30 -0
- package/dist/api/follow.d.ts +6 -0
- package/dist/api/follow.js +38 -0
- package/dist/api/helpers.d.ts +4 -0
- package/dist/api/helpers.js +26 -0
- package/dist/api/index.d.ts +14 -0
- package/dist/api/index.js +14 -0
- package/dist/api/investments.d.ts +21 -0
- package/dist/api/investments.js +135 -0
- package/dist/api/notifications.d.ts +4 -0
- package/dist/api/notifications.js +24 -0
- package/dist/api/orders.d.ts +8 -0
- package/dist/api/orders.js +40 -0
- package/dist/api/points.d.ts +5 -0
- package/dist/api/points.js +32 -0
- package/dist/api/poolReviews.d.ts +4 -0
- package/dist/api/poolReviews.js +23 -0
- package/dist/api/pools.d.ts +41 -0
- package/dist/api/pools.js +149 -0
- package/dist/api/priceData.d.ts +2 -0
- package/dist/api/priceData.js +9 -0
- package/dist/api/rainBurn.d.ts +3 -0
- package/dist/api/rainBurn.js +15 -0
- package/dist/api/types.d.ts +292 -0
- package/dist/api/types.js +2 -0
- package/dist/api/users.d.ts +15 -0
- package/dist/api/users.js +60 -0
- package/dist/auth/login.d.ts +4 -0
- package/dist/auth/login.js +27 -0
- package/dist/auth/types.d.ts +16 -0
- package/dist/auth/types.js +1 -0
- package/dist/config/environments.d.ts +15 -0
- package/dist/config/environments.js +41 -0
- package/dist/constants/contractmethods.d.ts +15 -0
- package/dist/constants/contractmethods.js +15 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +6 -0
- package/dist/markets/getDisputeFee.d.ts +5 -0
- package/dist/markets/getDisputeFee.js +19 -0
- package/dist/markets/getOrderInfo.d.ts +53 -0
- package/dist/markets/getOrderInfo.js +80 -0
- package/dist/markets/getResolverBondAmount.d.ts +9 -0
- package/dist/markets/getResolverBondAmount.js +35 -0
- package/dist/markets/getUserOptionLPShares.d.ts +7 -0
- package/dist/markets/getUserOptionLPShares.js +17 -0
- package/dist/markets/getUserOptionShares.d.ts +8 -0
- package/dist/markets/getUserOptionShares.js +17 -0
- package/dist/socket/RainSocket.d.ts +175 -0
- package/dist/socket/RainSocket.js +186 -0
- package/dist/tx/CreateMarket/buildCreateMarketRawTx.d.ts +2 -0
- package/dist/tx/CreateMarket/buildCreateMarketRawTx.js +55 -0
- package/dist/tx/CreateMarket/createMarketValidation.d.ts +2 -0
- package/dist/tx/CreateMarket/createMarketValidation.js +48 -0
- package/dist/tx/CreateMarket/helpers.d.ts +3 -0
- package/dist/tx/CreateMarket/helpers.js +42 -0
- package/dist/tx/buildAddLiquidityRawTx.d.ts +2 -0
- package/dist/tx/buildAddLiquidityRawTx.js +23 -0
- package/dist/tx/buildApprovalRawTx.d.ts +2 -0
- package/dist/tx/buildApprovalRawTx.js +24 -0
- package/dist/tx/buildCalculateWinnerRawTx.d.ts +13 -0
- package/dist/tx/buildCalculateWinnerRawTx.js +37 -0
- package/dist/tx/buildCancelOrdersRawTx.d.ts +3 -0
- package/dist/tx/buildCancelOrdersRawTx.js +43 -0
- package/dist/tx/buildClaimRawTx.d.ts +2 -0
- package/dist/tx/buildClaimRawTx.js +19 -0
- package/dist/tx/buildClosePoolRawTx.d.ts +20 -0
- package/dist/tx/buildClosePoolRawTx.js +95 -0
- package/dist/tx/buildEnterOptionRawTx.d.ts +2 -0
- package/dist/tx/buildEnterOptionRawTx.js +25 -0
- package/dist/tx/buildMergeRawTx.d.ts +2 -0
- package/dist/tx/buildMergeRawTx.js +21 -0
- package/dist/tx/buildOpenDisputeRawTx.d.ts +8 -0
- package/dist/tx/buildOpenDisputeRawTx.js +39 -0
- package/dist/tx/buildPlaceOrderRawTx.d.ts +3 -0
- package/dist/tx/buildPlaceOrderRawTx.js +47 -0
- package/dist/tx/buildRemoveLiquidityRawTx.d.ts +2 -0
- package/dist/tx/buildRemoveLiquidityRawTx.js +23 -0
- package/dist/tx/buildSplitRawTx.d.ts +2 -0
- package/dist/tx/buildSplitRawTx.js +21 -0
- package/dist/tx/types.d.ts +117 -0
- package/dist/tx/types.js +10 -0
- package/dist/types.d.ts +15 -0
- package/dist/types.js +1 -0
- package/dist/utils/helpers.d.ts +4 -0
- package/dist/utils/helpers.js +28 -0
- package/package.json +66 -0
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import { io } from 'socket.io-client';
|
|
2
|
+
export class RainSocket {
|
|
3
|
+
socket = null;
|
|
4
|
+
url;
|
|
5
|
+
listeners = new Map();
|
|
6
|
+
constructor(url) {
|
|
7
|
+
this.url = url;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Connect to the Socket.IO server
|
|
11
|
+
*/
|
|
12
|
+
connect() {
|
|
13
|
+
if (this.socket?.connected)
|
|
14
|
+
return;
|
|
15
|
+
this.socket = io(this.url, {
|
|
16
|
+
transports: ['websocket', 'polling'],
|
|
17
|
+
});
|
|
18
|
+
this.socket.on('connect', () => {
|
|
19
|
+
console.log('[RainSocket] Connected:', this.socket?.id);
|
|
20
|
+
// Re-register all listeners after reconnect
|
|
21
|
+
for (const [channel, callbacks] of this.listeners.entries()) {
|
|
22
|
+
for (const cb of callbacks) {
|
|
23
|
+
this.socket.on(channel, cb);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
this.socket.on('disconnect', (reason) => {
|
|
28
|
+
console.log('[RainSocket] Disconnected:', reason);
|
|
29
|
+
});
|
|
30
|
+
this.socket.on('connect_error', (err) => {
|
|
31
|
+
console.error('[RainSocket] Connection error:', err.message);
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Disconnect from the server
|
|
36
|
+
*/
|
|
37
|
+
disconnect() {
|
|
38
|
+
if (this.socket) {
|
|
39
|
+
this.socket.removeAllListeners();
|
|
40
|
+
this.socket.disconnect();
|
|
41
|
+
this.socket = null;
|
|
42
|
+
}
|
|
43
|
+
this.listeners.clear();
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Check if connected
|
|
47
|
+
*/
|
|
48
|
+
get isConnected() {
|
|
49
|
+
return this.socket?.connected ?? false;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Subscribe to an event for a specific pool
|
|
53
|
+
* @returns unsubscribe function
|
|
54
|
+
*/
|
|
55
|
+
on(event, poolId, callback) {
|
|
56
|
+
const channel = `${event}/${poolId}`;
|
|
57
|
+
return this.onChannel(channel, callback);
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Subscribe to a global event (no poolId)
|
|
61
|
+
* @returns unsubscribe function
|
|
62
|
+
*/
|
|
63
|
+
onGlobal(event, callback) {
|
|
64
|
+
return this.onChannel(event, callback);
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Subscribe to a raw channel name
|
|
68
|
+
* @returns unsubscribe function
|
|
69
|
+
*/
|
|
70
|
+
onChannel(channel, callback) {
|
|
71
|
+
if (!this.listeners.has(channel)) {
|
|
72
|
+
this.listeners.set(channel, new Set());
|
|
73
|
+
}
|
|
74
|
+
this.listeners.get(channel).add(callback);
|
|
75
|
+
if (this.socket) {
|
|
76
|
+
this.socket.on(channel, callback);
|
|
77
|
+
}
|
|
78
|
+
return () => {
|
|
79
|
+
this.listeners.get(channel)?.delete(callback);
|
|
80
|
+
if (this.socket) {
|
|
81
|
+
this.socket.off(channel, callback);
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
// ─── Typed helpers ──────────────────────────────────────────────────────────
|
|
86
|
+
onEnterOption(poolId, callback) {
|
|
87
|
+
return this.on('enter-option', poolId, callback);
|
|
88
|
+
}
|
|
89
|
+
onExitOption(poolId, callback) {
|
|
90
|
+
return this.on('exit-option', poolId, callback);
|
|
91
|
+
}
|
|
92
|
+
onLiquidity(poolId, callback) {
|
|
93
|
+
return this.on('liquidity', poolId, callback);
|
|
94
|
+
}
|
|
95
|
+
onSplit(poolId, callback) {
|
|
96
|
+
return this.on('split', poolId, callback);
|
|
97
|
+
}
|
|
98
|
+
onMerge(poolId, callback) {
|
|
99
|
+
return this.on('merge', poolId, callback);
|
|
100
|
+
}
|
|
101
|
+
onRemoveLiquidity(poolId, callback) {
|
|
102
|
+
return this.on('remove-liquidity', poolId, callback);
|
|
103
|
+
}
|
|
104
|
+
onSyncPrice(poolId, callback) {
|
|
105
|
+
return this.on('sync-price', poolId, callback);
|
|
106
|
+
}
|
|
107
|
+
onOrderCreated(poolId, callback) {
|
|
108
|
+
return this.on('order-created', poolId, callback);
|
|
109
|
+
}
|
|
110
|
+
onOrderCancelled(poolId, callback) {
|
|
111
|
+
return this.on('order-cancelled', poolId, callback);
|
|
112
|
+
}
|
|
113
|
+
onOrderFilled(poolId, callback) {
|
|
114
|
+
return this.on('order-filled', poolId, callback);
|
|
115
|
+
}
|
|
116
|
+
onPoolClosed(poolId, callback) {
|
|
117
|
+
return this.on('pool-closed', poolId, callback);
|
|
118
|
+
}
|
|
119
|
+
onPoolReverted(poolId, callback) {
|
|
120
|
+
return this.on('pool-reverted', poolId, callback);
|
|
121
|
+
}
|
|
122
|
+
onPoolTokenSet(poolId, callback) {
|
|
123
|
+
return this.on('pool-token-set', poolId, callback);
|
|
124
|
+
}
|
|
125
|
+
onStreamingStatusChanged(poolId, callback) {
|
|
126
|
+
return this.on('streamingStatusChanged', poolId, callback);
|
|
127
|
+
}
|
|
128
|
+
onNewPool(callback) {
|
|
129
|
+
return this.onGlobal('pool', callback);
|
|
130
|
+
}
|
|
131
|
+
// ─── Dispute & Appeal events ────────────────────────────────────────────────
|
|
132
|
+
onWinner(poolId, callback) {
|
|
133
|
+
return this.on('winner', poolId, callback);
|
|
134
|
+
}
|
|
135
|
+
onWinnerProposer(poolId, callback) {
|
|
136
|
+
return this.on('winner-proposer', poolId, callback);
|
|
137
|
+
}
|
|
138
|
+
onRevealWinnerAvailable(poolId, callback) {
|
|
139
|
+
return this.on('reveal-winner-available', poolId, callback);
|
|
140
|
+
}
|
|
141
|
+
onDisputeOpened(poolId, callback) {
|
|
142
|
+
return this.on('dispute-opened', poolId, callback);
|
|
143
|
+
}
|
|
144
|
+
onOracleCreated(poolId, callback) {
|
|
145
|
+
return this.on('oracle-created', poolId, callback);
|
|
146
|
+
}
|
|
147
|
+
onDisputeTimeExtended(poolId, callback) {
|
|
148
|
+
return this.on('dispute-time-extented', poolId, callback);
|
|
149
|
+
}
|
|
150
|
+
onAppealOpened(poolId, callback) {
|
|
151
|
+
return this.on('appeal-opened', poolId, callback);
|
|
152
|
+
}
|
|
153
|
+
onAppealWinnerCalculated(poolId, callback) {
|
|
154
|
+
return this.on('appeal-winner-calculated', poolId, callback);
|
|
155
|
+
}
|
|
156
|
+
onDisputeWinner(poolId, callback) {
|
|
157
|
+
return this.on('dispute-winner', poolId, callback);
|
|
158
|
+
}
|
|
159
|
+
onAppealWinner(poolId, callback) {
|
|
160
|
+
return this.on('appeal-winner', poolId, callback);
|
|
161
|
+
}
|
|
162
|
+
onClaimReward(poolId, callback) {
|
|
163
|
+
return this.on('claim-reward', poolId, callback);
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* User-scoped claim reward event: claim-reward/{poolId}/{userId}
|
|
167
|
+
*/
|
|
168
|
+
onUserClaimReward(poolId, userId, callback) {
|
|
169
|
+
return this.onChannel(`claim-reward/${poolId}/${userId}`, callback);
|
|
170
|
+
}
|
|
171
|
+
onDisputeRefund(poolId, userId, callback) {
|
|
172
|
+
return this.onChannel(`dispute-refund/${poolId}/${userId}`, callback);
|
|
173
|
+
}
|
|
174
|
+
onAppealRefund(poolId, userId, callback) {
|
|
175
|
+
return this.onChannel(`appeal-refund/${poolId}/${userId}`, callback);
|
|
176
|
+
}
|
|
177
|
+
onResolutionRefund(poolId, userId, callback) {
|
|
178
|
+
return this.onChannel(`resolution-refund/${poolId}/${userId}`, callback);
|
|
179
|
+
}
|
|
180
|
+
onResolverReward(poolId, userId, callback) {
|
|
181
|
+
return this.onChannel(`resolver-reward/${poolId}/${userId}`, callback);
|
|
182
|
+
}
|
|
183
|
+
onNotifications(userId, callback) {
|
|
184
|
+
return this.onChannel(`notifications/${userId}`, callback);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { encodeFunctionData } from "viem";
|
|
2
|
+
import { CreateMarketAbi } from "../../abi/CreateMarketAbi.js";
|
|
3
|
+
import { CREATE_MARKET } from "../../constants/contractmethods.js";
|
|
4
|
+
import { validateCreateMarketParams } from "./createMarketValidation.js";
|
|
5
|
+
import { normalizeBarValues, uploadMetaData } from "./helpers.js";
|
|
6
|
+
import { getUserAllowance } from "../../utils/helpers.js";
|
|
7
|
+
import { buildApproveRawTx } from "../buildApprovalRawTx.js";
|
|
8
|
+
const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
|
|
9
|
+
export async function buildCreateMarketRawTx(params) {
|
|
10
|
+
const { isPublic, isPublicPoolResolverAi, creator, startTime, endTime, no_of_options, disputeTimer, inputAmountWei, barValues, baseToken, tradingModel, factoryContractAddress, oracleFixedFeePerOption, } = params;
|
|
11
|
+
if (!factoryContractAddress)
|
|
12
|
+
throw new Error("environment is not set correctly, factory contract address is missing");
|
|
13
|
+
validateCreateMarketParams(params);
|
|
14
|
+
// Approval = liquidity + oracle fixed fee (fee per option * number of options)
|
|
15
|
+
const oracleFee = (oracleFixedFeePerOption ?? 0n) * BigInt(no_of_options);
|
|
16
|
+
const approvalAmount = inputAmountWei + oracleFee;
|
|
17
|
+
const allowance = await getUserAllowance(params);
|
|
18
|
+
const createMarketTransactions = [];
|
|
19
|
+
if (BigInt(allowance) < approvalAmount) {
|
|
20
|
+
const approveTx = buildApproveRawTx({ spender: factoryContractAddress, tokenAddress: baseToken, amount: approvalAmount });
|
|
21
|
+
createMarketTransactions.push(approveTx);
|
|
22
|
+
}
|
|
23
|
+
const normalizeBarValue = normalizeBarValues(barValues);
|
|
24
|
+
const liquidityPercentages = normalizeBarValue.map((v) => BigInt(v));
|
|
25
|
+
const ipfsUrl = await uploadMetaData(params);
|
|
26
|
+
// oracleEndTime = endTime + disputeTimer (seconds)
|
|
27
|
+
const oracleEndTime = BigInt(endTime) + BigInt(disputeTimer);
|
|
28
|
+
const createMarketParams = {
|
|
29
|
+
isPublic,
|
|
30
|
+
resolverIsAI: isPublicPoolResolverAi,
|
|
31
|
+
poolOwner: creator,
|
|
32
|
+
referrer: ZERO_ADDRESS,
|
|
33
|
+
startTime,
|
|
34
|
+
endTime,
|
|
35
|
+
numberOfOptions: no_of_options,
|
|
36
|
+
oracleEndTime,
|
|
37
|
+
ipfsUri: ipfsUrl,
|
|
38
|
+
initialLiquidity: inputAmountWei,
|
|
39
|
+
liquidityPercentages,
|
|
40
|
+
poolResolver: ZERO_ADDRESS,
|
|
41
|
+
baseToken,
|
|
42
|
+
tradingModel: tradingModel ?? 0,
|
|
43
|
+
};
|
|
44
|
+
console.log('createMarketParams: ', createMarketParams);
|
|
45
|
+
createMarketTransactions.push({
|
|
46
|
+
to: factoryContractAddress,
|
|
47
|
+
data: encodeFunctionData({
|
|
48
|
+
abi: CreateMarketAbi,
|
|
49
|
+
functionName: CREATE_MARKET,
|
|
50
|
+
args: [createMarketParams],
|
|
51
|
+
}),
|
|
52
|
+
value: 0n,
|
|
53
|
+
});
|
|
54
|
+
return createMarketTransactions;
|
|
55
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
export function validateCreateMarketParams(params) {
|
|
2
|
+
const { marketQuestion, marketOptions, marketTags, marketDescription, isPublic, isPublicPoolResolverAi, creator, startTime, endTime, no_of_options, inputAmountWei, barValues, baseToken, factoryContractAddress, tokenDecimals, } = params;
|
|
3
|
+
// Required field validations
|
|
4
|
+
if (typeof isPublic !== "boolean")
|
|
5
|
+
throw new Error("isPublic is required and must be a boolean");
|
|
6
|
+
if (typeof isPublicPoolResolverAi !== "boolean")
|
|
7
|
+
throw new Error("isPublicPoolResolverAi is required and must be a boolean");
|
|
8
|
+
if (!creator)
|
|
9
|
+
throw new Error("creator address is required");
|
|
10
|
+
if (!marketQuestion)
|
|
11
|
+
throw new Error("question is required");
|
|
12
|
+
if (!marketDescription)
|
|
13
|
+
throw new Error("description is required");
|
|
14
|
+
if (!Array.isArray(marketOptions) || marketOptions.length < 3 || marketOptions.length > 26) {
|
|
15
|
+
throw new Error("options must be between 3 and 26");
|
|
16
|
+
}
|
|
17
|
+
if (marketOptions.some(opt => !opt?.toString().trim())) {
|
|
18
|
+
throw new Error("options cannot contain empty values");
|
|
19
|
+
}
|
|
20
|
+
if (!Array.isArray(marketTags) || marketTags.length < 1 || marketTags.length > 3) {
|
|
21
|
+
throw new Error("tags must be between 1 and 3");
|
|
22
|
+
}
|
|
23
|
+
if (marketTags.some(tag => !tag?.toString().trim())) {
|
|
24
|
+
throw new Error("tags cannot contain empty values");
|
|
25
|
+
}
|
|
26
|
+
if (!startTime)
|
|
27
|
+
throw new Error("startTime is required");
|
|
28
|
+
if (!endTime)
|
|
29
|
+
throw new Error("endTime is required");
|
|
30
|
+
if (!no_of_options)
|
|
31
|
+
throw new Error("number of options is required and cannot be empty");
|
|
32
|
+
if (!inputAmountWei)
|
|
33
|
+
throw new Error("inputAmountWei is required");
|
|
34
|
+
if (!barValues || !Array.isArray(barValues) || barValues.length === 0)
|
|
35
|
+
throw new Error("barValues array is required and cannot be empty");
|
|
36
|
+
if (!baseToken)
|
|
37
|
+
throw new Error("baseToken address is required");
|
|
38
|
+
if (!factoryContractAddress)
|
|
39
|
+
throw new Error("factoryContractAddress is required");
|
|
40
|
+
const decimals = tokenDecimals ?? 6;
|
|
41
|
+
const oneTokenInWei = 10n ** BigInt(decimals);
|
|
42
|
+
if (inputAmountWei < oneTokenInWei * 10n) {
|
|
43
|
+
throw new Error("Market cannot be opened: inputAmountWei must be at least $10");
|
|
44
|
+
}
|
|
45
|
+
if (startTime >= endTime)
|
|
46
|
+
throw new Error("startTime must be earlier than endTime");
|
|
47
|
+
return true;
|
|
48
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
export function normalizeBarValues(values) {
|
|
2
|
+
const transformedBarValues = [
|
|
3
|
+
...values.map((value) => Math.floor(value * 100)),
|
|
4
|
+
];
|
|
5
|
+
const totalRounded = transformedBarValues.reduce((sum, val) => sum + val, 0);
|
|
6
|
+
const difference = 10000 - totalRounded;
|
|
7
|
+
if (difference !== 0) {
|
|
8
|
+
transformedBarValues[transformedBarValues.length - 1] += difference;
|
|
9
|
+
}
|
|
10
|
+
return transformedBarValues;
|
|
11
|
+
}
|
|
12
|
+
export async function uploadMetaData(params) {
|
|
13
|
+
const { marketQuestion, marketOptions, marketTags, marketDescription, isPublic, isPublicPoolResolverAi, startTime, endTime, no_of_options, creator, tradingModel, apiUrl, } = params;
|
|
14
|
+
const formattedStartDate = new Date(Number(startTime) * 1000).toISOString();
|
|
15
|
+
const formattedEndDate = new Date(Number(endTime) * 1000).toISOString();
|
|
16
|
+
const metadata = {
|
|
17
|
+
question: marketQuestion,
|
|
18
|
+
isPrivate: !isPublic,
|
|
19
|
+
options: Array.isArray(marketOptions) ? marketOptions : [],
|
|
20
|
+
startDate: formattedStartDate,
|
|
21
|
+
endDate: formattedEndDate,
|
|
22
|
+
tradingModel: tradingModel ?? 0,
|
|
23
|
+
questionImage: params.questionImage ?? '',
|
|
24
|
+
tags: marketTags,
|
|
25
|
+
poolDescription: marketDescription,
|
|
26
|
+
isAiResolver: isPublicPoolResolverAi,
|
|
27
|
+
};
|
|
28
|
+
const res = await fetch(`${apiUrl}/ipfs/upload`, {
|
|
29
|
+
method: "POST",
|
|
30
|
+
headers: {
|
|
31
|
+
"Content-Type": "application/json",
|
|
32
|
+
...(apiUrl?.includes('ngrok') ? { "ngrok-skip-browser-warning": "true" } : {}),
|
|
33
|
+
},
|
|
34
|
+
body: JSON.stringify(metadata),
|
|
35
|
+
});
|
|
36
|
+
if (!res.ok) {
|
|
37
|
+
const errorText = await res.text().catch(() => res.statusText);
|
|
38
|
+
throw new Error(`Failed to upload metadata: ${res.status} — ${errorText}`);
|
|
39
|
+
}
|
|
40
|
+
const data = await res.json();
|
|
41
|
+
return data?.data?.ipfsHash;
|
|
42
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { encodeFunctionData } from "viem";
|
|
2
|
+
import { MarketsAbi } from "../abi/MarketsAbi.js";
|
|
3
|
+
import { ENTER_LIQUIDITY } from "../constants/contractmethods.js";
|
|
4
|
+
export function buildAddLiquidityRawTx(params) {
|
|
5
|
+
const { marketContractAddress, option, totalAmountInWei } = params;
|
|
6
|
+
if (!marketContractAddress)
|
|
7
|
+
throw new Error("marketContractAddress is required");
|
|
8
|
+
if (option === undefined || option === null)
|
|
9
|
+
throw new Error("option is required");
|
|
10
|
+
if (!totalAmountInWei)
|
|
11
|
+
throw new Error("totalAmountInWei is required");
|
|
12
|
+
if (totalAmountInWei <= 0n)
|
|
13
|
+
throw new Error("totalAmountInWei must be greater than 0");
|
|
14
|
+
return {
|
|
15
|
+
to: marketContractAddress,
|
|
16
|
+
data: encodeFunctionData({
|
|
17
|
+
abi: MarketsAbi,
|
|
18
|
+
functionName: ENTER_LIQUIDITY,
|
|
19
|
+
args: [option, totalAmountInWei],
|
|
20
|
+
}),
|
|
21
|
+
value: 0n,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { encodeFunctionData } from "viem";
|
|
2
|
+
import { ERC20Abi } from "../abi/ERC20Abi.js";
|
|
3
|
+
import { APPROVE_TOKEN } from "../constants/contractmethods.js";
|
|
4
|
+
export function buildApproveRawTx(params) {
|
|
5
|
+
const { tokenAddress, spender, amount } = params;
|
|
6
|
+
if (!tokenAddress)
|
|
7
|
+
throw new Error("token address is required");
|
|
8
|
+
if (!spender)
|
|
9
|
+
throw new Error("spender address is required");
|
|
10
|
+
if (amount === undefined || amount === null) {
|
|
11
|
+
throw new Error("amount is required; pass a finite bigint (infinite approvals are no longer supported)");
|
|
12
|
+
}
|
|
13
|
+
if (amount <= 0n)
|
|
14
|
+
throw new Error("amount must be greater than 0");
|
|
15
|
+
return {
|
|
16
|
+
to: tokenAddress,
|
|
17
|
+
data: encodeFunctionData({
|
|
18
|
+
abi: ERC20Abi,
|
|
19
|
+
functionName: APPROVE_TOKEN,
|
|
20
|
+
args: [spender, amount],
|
|
21
|
+
}),
|
|
22
|
+
value: 0n,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { RawTransaction } from "./types.js";
|
|
2
|
+
export interface CalculateWinnerTxParams {
|
|
3
|
+
marketContractAddress: `0x${string}`;
|
|
4
|
+
option: bigint;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Builds calculateWinner TX.
|
|
8
|
+
* 1. Reads optionResolver(option) from market contract to get the resolver address for that option
|
|
9
|
+
* 2. Encodes calculateWinner() call to that resolver
|
|
10
|
+
*/
|
|
11
|
+
export declare function buildCalculateWinnerRawTx(params: CalculateWinnerTxParams & {
|
|
12
|
+
rpcUrl: string;
|
|
13
|
+
}): Promise<RawTransaction>;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { encodeFunctionData, createPublicClient, http, parseAbi } from "viem";
|
|
2
|
+
import { arbitrum } from "viem/chains";
|
|
3
|
+
import { OracleAbi } from "../abi/OracleAbi.js";
|
|
4
|
+
const optionResolverAbi = parseAbi(['function optionResolver(uint256 option) view returns (address)']);
|
|
5
|
+
/**
|
|
6
|
+
* Builds calculateWinner TX.
|
|
7
|
+
* 1. Reads optionResolver(option) from market contract to get the resolver address for that option
|
|
8
|
+
* 2. Encodes calculateWinner() call to that resolver
|
|
9
|
+
*/
|
|
10
|
+
export async function buildCalculateWinnerRawTx(params) {
|
|
11
|
+
const { marketContractAddress, option, rpcUrl } = params;
|
|
12
|
+
if (!marketContractAddress)
|
|
13
|
+
throw new Error("marketContractAddress is required");
|
|
14
|
+
if (option === undefined || option === null)
|
|
15
|
+
throw new Error("option is required");
|
|
16
|
+
const client = createPublicClient({
|
|
17
|
+
chain: arbitrum,
|
|
18
|
+
transport: http(rpcUrl),
|
|
19
|
+
});
|
|
20
|
+
const resolverAddress = await client.readContract({
|
|
21
|
+
address: marketContractAddress,
|
|
22
|
+
abi: optionResolverAbi,
|
|
23
|
+
functionName: 'optionResolver',
|
|
24
|
+
args: [option],
|
|
25
|
+
});
|
|
26
|
+
if (!resolverAddress || resolverAddress === '0x0000000000000000000000000000000000000000') {
|
|
27
|
+
throw new Error("No resolver set for this option");
|
|
28
|
+
}
|
|
29
|
+
return {
|
|
30
|
+
to: resolverAddress,
|
|
31
|
+
data: encodeFunctionData({
|
|
32
|
+
abi: OracleAbi,
|
|
33
|
+
functionName: 'calculateWinner',
|
|
34
|
+
}),
|
|
35
|
+
value: 0n,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { CancelBuyOrdersTxParams, CancelSellOrdersTxParams, RawTransaction } from "./types.js";
|
|
2
|
+
export declare function buildCancelBuyOrdersRawTx(params: CancelBuyOrdersTxParams): RawTransaction;
|
|
3
|
+
export declare function buildCancelSellOrdersRawTx(params: CancelSellOrdersTxParams): RawTransaction;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { encodeFunctionData } from "viem";
|
|
2
|
+
import { MarketsAbi } from "../abi/MarketsAbi.js";
|
|
3
|
+
import { CANCEL_BUY_ORDERS, CANCEL_SELL_ORDERS } from "../constants/contractmethods.js";
|
|
4
|
+
export function buildCancelBuyOrdersRawTx(params) {
|
|
5
|
+
const { marketContractAddress, option, optionSides, prices, orderIDs } = params;
|
|
6
|
+
if (!marketContractAddress)
|
|
7
|
+
throw new Error("marketContractAddress is required");
|
|
8
|
+
if (option === undefined || option === null)
|
|
9
|
+
throw new Error("option is required");
|
|
10
|
+
if (!optionSides.length || !prices.length || !orderIDs.length)
|
|
11
|
+
throw new Error("optionSides, prices, and orderIDs arrays are required");
|
|
12
|
+
if (optionSides.length !== prices.length || prices.length !== orderIDs.length)
|
|
13
|
+
throw new Error("optionSides, prices, and orderIDs must have the same length");
|
|
14
|
+
return {
|
|
15
|
+
to: marketContractAddress,
|
|
16
|
+
data: encodeFunctionData({
|
|
17
|
+
abi: MarketsAbi,
|
|
18
|
+
functionName: CANCEL_BUY_ORDERS,
|
|
19
|
+
args: [option, optionSides, prices, orderIDs],
|
|
20
|
+
}),
|
|
21
|
+
value: 0n,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
export function buildCancelSellOrdersRawTx(params) {
|
|
25
|
+
const { marketContractAddress, option, optionSides, prices, orderIDs } = params;
|
|
26
|
+
if (!marketContractAddress)
|
|
27
|
+
throw new Error("marketContractAddress is required");
|
|
28
|
+
if (option === undefined || option === null)
|
|
29
|
+
throw new Error("option is required");
|
|
30
|
+
if (!optionSides.length || !prices.length || !orderIDs.length)
|
|
31
|
+
throw new Error("optionSides, prices, and orderIDs arrays are required");
|
|
32
|
+
if (optionSides.length !== prices.length || prices.length !== orderIDs.length)
|
|
33
|
+
throw new Error("optionSides, prices, and orderIDs must have the same length");
|
|
34
|
+
return {
|
|
35
|
+
to: marketContractAddress,
|
|
36
|
+
data: encodeFunctionData({
|
|
37
|
+
abi: MarketsAbi,
|
|
38
|
+
functionName: CANCEL_SELL_ORDERS,
|
|
39
|
+
args: [option, optionSides, prices, orderIDs],
|
|
40
|
+
}),
|
|
41
|
+
value: 0n,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { encodeFunctionData } from "viem";
|
|
2
|
+
import { MarketsAbi } from "../abi/MarketsAbi.js";
|
|
3
|
+
import { CLAIM } from "../constants/contractmethods.js";
|
|
4
|
+
export function buildClaimRawTx(params) {
|
|
5
|
+
const { marketContractAddress, option } = params;
|
|
6
|
+
if (!marketContractAddress)
|
|
7
|
+
throw new Error("marketContractAddress is required");
|
|
8
|
+
if (option === undefined || option === null)
|
|
9
|
+
throw new Error("option is required");
|
|
10
|
+
return {
|
|
11
|
+
to: marketContractAddress,
|
|
12
|
+
data: encodeFunctionData({
|
|
13
|
+
abi: MarketsAbi,
|
|
14
|
+
functionName: CLAIM,
|
|
15
|
+
args: [option],
|
|
16
|
+
}),
|
|
17
|
+
value: 0n,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { ClosePoolAITxParams, ClosePoolManualTxParams, ChooseWinnerTxParams, RawTransaction } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Close pool with AI resolver — no winner proposed, AI decides.
|
|
4
|
+
* Returns [approval, closePool] transactions.
|
|
5
|
+
*/
|
|
6
|
+
export declare function buildClosePoolAIRawTx(params: ClosePoolAITxParams & {
|
|
7
|
+
rpcUrl: string;
|
|
8
|
+
}): Promise<RawTransaction[]>;
|
|
9
|
+
/**
|
|
10
|
+
* Close pool with manual resolver — proposer suggests a winning side.
|
|
11
|
+
* Returns [approval, closePool] transactions.
|
|
12
|
+
*/
|
|
13
|
+
export declare function buildClosePoolManualRawTx(params: ClosePoolManualTxParams & {
|
|
14
|
+
rpcUrl: string;
|
|
15
|
+
}): Promise<RawTransaction[]>;
|
|
16
|
+
/**
|
|
17
|
+
* Choose/finalize the winner after pool is closed.
|
|
18
|
+
* chooseWinner(option, optionSide)
|
|
19
|
+
*/
|
|
20
|
+
export declare function buildChooseWinnerRawTx(params: ChooseWinnerTxParams): RawTransaction;
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { encodeFunctionData } from "viem";
|
|
2
|
+
import { MarketsAbi } from "../abi/MarketsAbi.js";
|
|
3
|
+
import { CLOSE_POOL, CHOOSE_WINNER } from "../constants/contractmethods.js";
|
|
4
|
+
import { getResolverBondAmount, getMarketBaseToken } from "../markets/getResolverBondAmount.js";
|
|
5
|
+
import { buildApproveRawTx } from "./buildApprovalRawTx.js";
|
|
6
|
+
/**
|
|
7
|
+
* Close pool with AI resolver — no winner proposed, AI decides.
|
|
8
|
+
* Returns [approval, closePool] transactions.
|
|
9
|
+
*/
|
|
10
|
+
export async function buildClosePoolAIRawTx(params) {
|
|
11
|
+
const { marketContractAddress, option, rpcUrl } = params;
|
|
12
|
+
if (!marketContractAddress)
|
|
13
|
+
throw new Error("marketContractAddress is required");
|
|
14
|
+
if (option === undefined || option === null)
|
|
15
|
+
throw new Error("option is required");
|
|
16
|
+
const [bondAmount, baseToken] = await Promise.all([
|
|
17
|
+
getResolverBondAmount({ marketContractAddress, option, rpcUrl }),
|
|
18
|
+
getMarketBaseToken({ marketContractAddress, rpcUrl }),
|
|
19
|
+
]);
|
|
20
|
+
const txs = [];
|
|
21
|
+
if (bondAmount > 0n) {
|
|
22
|
+
txs.push(buildApproveRawTx({
|
|
23
|
+
tokenAddress: baseToken,
|
|
24
|
+
spender: marketContractAddress,
|
|
25
|
+
amount: bondAmount,
|
|
26
|
+
}));
|
|
27
|
+
}
|
|
28
|
+
txs.push({
|
|
29
|
+
to: marketContractAddress,
|
|
30
|
+
data: encodeFunctionData({
|
|
31
|
+
abi: MarketsAbi,
|
|
32
|
+
functionName: CLOSE_POOL,
|
|
33
|
+
args: [option],
|
|
34
|
+
}),
|
|
35
|
+
value: 0n,
|
|
36
|
+
});
|
|
37
|
+
return txs;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Close pool with manual resolver — proposer suggests a winning side.
|
|
41
|
+
* Returns [approval, closePool] transactions.
|
|
42
|
+
*/
|
|
43
|
+
export async function buildClosePoolManualRawTx(params) {
|
|
44
|
+
const { marketContractAddress, option, proposedWinner, rpcUrl } = params;
|
|
45
|
+
if (!marketContractAddress)
|
|
46
|
+
throw new Error("marketContractAddress is required");
|
|
47
|
+
if (option === undefined || option === null)
|
|
48
|
+
throw new Error("option is required");
|
|
49
|
+
if (proposedWinner === undefined || proposedWinner === null)
|
|
50
|
+
throw new Error("proposedWinner is required");
|
|
51
|
+
const [bondAmount, baseToken] = await Promise.all([
|
|
52
|
+
getResolverBondAmount({ marketContractAddress, option, rpcUrl }),
|
|
53
|
+
getMarketBaseToken({ marketContractAddress, rpcUrl }),
|
|
54
|
+
]);
|
|
55
|
+
const txs = [];
|
|
56
|
+
if (bondAmount > 0n) {
|
|
57
|
+
txs.push(buildApproveRawTx({
|
|
58
|
+
tokenAddress: baseToken,
|
|
59
|
+
spender: marketContractAddress,
|
|
60
|
+
amount: bondAmount,
|
|
61
|
+
}));
|
|
62
|
+
}
|
|
63
|
+
txs.push({
|
|
64
|
+
to: marketContractAddress,
|
|
65
|
+
data: encodeFunctionData({
|
|
66
|
+
abi: MarketsAbi,
|
|
67
|
+
functionName: CLOSE_POOL,
|
|
68
|
+
args: [option, proposedWinner],
|
|
69
|
+
}),
|
|
70
|
+
value: 0n,
|
|
71
|
+
});
|
|
72
|
+
return txs;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Choose/finalize the winner after pool is closed.
|
|
76
|
+
* chooseWinner(option, optionSide)
|
|
77
|
+
*/
|
|
78
|
+
export function buildChooseWinnerRawTx(params) {
|
|
79
|
+
const { marketContractAddress, option, optionSide } = params;
|
|
80
|
+
if (!marketContractAddress)
|
|
81
|
+
throw new Error("marketContractAddress is required");
|
|
82
|
+
if (option === undefined || option === null)
|
|
83
|
+
throw new Error("option is required");
|
|
84
|
+
if (optionSide === undefined || optionSide === null)
|
|
85
|
+
throw new Error("optionSide is required");
|
|
86
|
+
return {
|
|
87
|
+
to: marketContractAddress,
|
|
88
|
+
data: encodeFunctionData({
|
|
89
|
+
abi: MarketsAbi,
|
|
90
|
+
functionName: CHOOSE_WINNER,
|
|
91
|
+
args: [option, optionSide],
|
|
92
|
+
}),
|
|
93
|
+
value: 0n,
|
|
94
|
+
};
|
|
95
|
+
}
|