@continuumdao/ctm-mpc-defi 0.2.49 → 0.2.50

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.
@@ -0,0 +1,2308 @@
1
+ 'use strict';
2
+
3
+ var viem = require('viem');
4
+ var continuumNodeSdk = require('@continuumdao/continuum-node-sdk');
5
+
6
+ // src/core/registry.ts
7
+ var modules = [];
8
+ function registerProtocolModule(mod) {
9
+ const existing = modules.findIndex((m) => m.id === mod.id);
10
+ if (existing >= 0) {
11
+ modules[existing] = mod;
12
+ } else {
13
+ modules.push(mod);
14
+ }
15
+ }
16
+ var TRUEO_PROTOCOL_ID = "trueo";
17
+ var PREDICTION_MARKETS_PROTOCOL_ID = "prediction-markets";
18
+ var TRUEO_BASE_CHAIN_ID = 8453;
19
+ var TRUEO_CHAIN_IDS = [TRUEO_BASE_CHAIN_ID];
20
+ var TRUEO_NETWORK = "base-mainnet";
21
+ var TRUEO_API_ORIGIN = "https://api.trueo.com";
22
+ var TRUEO_MARKET_API_PREFIX = "/market";
23
+ function trueoMarketApiPath(suffix) {
24
+ const s = suffix.startsWith("/") ? suffix : `/${suffix}`;
25
+ return `${TRUEO_MARKET_API_PREFIX}${s}`;
26
+ }
27
+ var TRUEO_TYD = viem.getAddress("0xb13CF163d916917d9cD6E836905cA5f12a1dEF4B");
28
+ var TRUEO_TRUE = viem.getAddress("0x21CFCFc3d8F98fC728f48341D10Ad8283F6EB7AB");
29
+ var TRUEO_USDC = viem.getAddress("0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913");
30
+ var TRUEO_TRUTH_MARKET_MANAGER = viem.getAddress("0x61A98Bef11867c69489B91f340fE545eEfc695d7");
31
+ var TRUEO_ORDER_MANAGER = viem.getAddress("0x1cdB1C43eB64e99780EA9d3C7162C23432C59a1A");
32
+ var TRUEO_UNIVERSAL_ROUTER_ADAPTER = viem.getAddress("0x0A1AFc2121B4441127a02DEF72928F61f564034a");
33
+ var TRUEO_TRUTH_MARKET_ADAPTER = viem.getAddress("0x6E08d24AEf78F6d1a97503F64E84fDF65f8125E1");
34
+ var TRUEO_V4_HOOK = viem.getAddress("0x3E83479B2276EcFb7C7181F67b5d092d3511e0C4");
35
+ var TRUEO_PERMIT2 = viem.getAddress("0x000000000022D473030F116dDEE9F6B43aC78BA3");
36
+ var TRUEO_TYD_DECIMALS = 6;
37
+ var TRUEO_OUTCOME_TOKEN_DECIMALS = 18;
38
+ var TRUEO_BET_CLOSE_BUFFER_SECONDS = 5 * 60;
39
+ var TRUEO_PERMIT2_APPROVAL_SECONDS = 30 * 60;
40
+ var TRUEO_BET_ACTIONS = ["swap", "createOrder"];
41
+ function isTrueoChainSupported(chainId) {
42
+ return TRUEO_CHAIN_IDS.includes(chainId);
43
+ }
44
+ function assertTrueoChainId(chainId) {
45
+ if (!isTrueoChainSupported(chainId)) {
46
+ throw new Error(`Trueo is Base-only (chainId ${TRUEO_BASE_CHAIN_ID}).`);
47
+ }
48
+ }
49
+ function isTrueoCoreToken(address) {
50
+ try {
51
+ const n = viem.getAddress(address);
52
+ return n === TRUEO_TYD || n === TRUEO_TRUE;
53
+ } catch {
54
+ return false;
55
+ }
56
+ }
57
+ function normalizeTrueoAddress(address) {
58
+ return viem.getAddress(address);
59
+ }
60
+ var trueoErc20Abi = viem.parseAbi([
61
+ "function allowance(address owner, address spender) view returns (uint256)",
62
+ "function approve(address spender, uint256 amount) returns (bool)",
63
+ "function balanceOf(address account) view returns (uint256)",
64
+ "function decimals() view returns (uint8)",
65
+ "function symbol() view returns (string)"
66
+ ]);
67
+ var trueoMarketAbi = viem.parseAbi([
68
+ "function mint(uint256 paymentTokenAmount)",
69
+ "function burn(uint256 amount)",
70
+ "function redeem(uint256 amount)",
71
+ "function paymentToken() view returns (address)",
72
+ "function yesToken() view returns (address)",
73
+ "function noToken() view returns (address)",
74
+ "function getCurrentStatus() view returns (uint8)",
75
+ "function winningPosition() view returns (uint256)",
76
+ "function paused() view returns (bool)"
77
+ ]);
78
+ var trueoMarketV2Abi = viem.parseAbi([
79
+ "function getPoolKeys() view returns ((address currency0, address currency1, uint24 fee, int24 tickSpacing, address hooks) yesPoolKey, (address currency0, address currency1, uint24 fee, int24 tickSpacing, address hooks) noPoolKey)",
80
+ "function getPoolIds() view returns (bytes32 yesPoolId, bytes32 noPoolId)"
81
+ ]);
82
+ var trueoAdapterMintAbi = viem.parseAbi([
83
+ "function mint(address truthMarket, uint256 assetAmount)",
84
+ "function burn(address truthMarket, uint256 amount)",
85
+ "function redeem(address truthMarket, uint256 amount)"
86
+ ]);
87
+ var trueoTydVaultAbi = viem.parseAbi([
88
+ "function asset() view returns (address)",
89
+ "function deposit(uint256 assets, address receiver) returns (uint256 shares)",
90
+ "function redeem(uint256 shares, address receiver, address owner) returns (uint256 assets)"
91
+ ]);
92
+ var trueoUniversalRouterAdapterAbi = viem.parseAbi([
93
+ "function execute(bytes commands, bytes[] inputs, uint256 deadline) payable"
94
+ ]);
95
+ var trueoPermit2ApproveAbi = viem.parseAbi([
96
+ "function approve(address token, address spender, uint160 amount, uint48 expiration)",
97
+ "function allowance(address owner, address token, address spender) view returns (uint160 amount, uint48 expiration, uint48 nonce)"
98
+ ]);
99
+ var trueoOrderManagerAbi = viem.parseAbi([
100
+ "function createOrder((address currency0, address currency1, uint24 fee, int24 tickSpacing, address hooks) poolKey, uint128 amountIn, int24 tickLower, int24 tickUpper, bool zeroForOne, bool enablePartialFill) returns (uint32 orderId)",
101
+ "function cancelOrder((address currency0, address currency1, uint24 fee, int24 tickSpacing, address hooks) poolKey, uint32 orderId, uint128 amount0Min, uint128 amount1Min)",
102
+ "function pendingOrder(bytes32 poolId, uint32 orderId) view returns (address owner, bool zeroForOne, int24 tickLower, int24 tickUpper, uint256 liquidity, bool enablePartialFill)"
103
+ ]);
104
+ var trueoOrderManagerStructAbi = viem.parseAbi([
105
+ "function createOrder(((address currency0, address currency1, uint24 fee, int24 tickSpacing, address hooks) poolKey, uint128 amountIn, int24 tickLower, int24 tickUpper, bool zeroForOne, bool enablePartialFill) params) returns (uint32 orderId)",
106
+ "function cancelOrder(((address currency0, address currency1, uint24 fee, int24 tickSpacing, address hooks) poolKey, uint32 orderId, uint128 amount0Min, uint128 amount1Min) params)"
107
+ ]);
108
+ var UR_COMMAND_V4_SWAP = 16;
109
+ var V4_ACTION_SWAP_EXACT_IN_SINGLE = 6;
110
+ var V4_ACTION_SETTLE = 11;
111
+ var V4_ACTION_TAKE = 12;
112
+ var poolKeyComponents = [
113
+ { name: "currency0", type: "address" },
114
+ { name: "currency1", type: "address" },
115
+ { name: "fee", type: "uint24" },
116
+ { name: "tickSpacing", type: "int24" },
117
+ { name: "hooks", type: "address" }
118
+ ];
119
+ function encodeErc20Approve(spender, amount) {
120
+ return viem.encodeFunctionData({
121
+ abi: trueoErc20Abi,
122
+ functionName: "approve",
123
+ args: [viem.getAddress(spender), amount]
124
+ });
125
+ }
126
+ function encodePermit2Approve(args) {
127
+ return viem.encodeFunctionData({
128
+ abi: trueoPermit2ApproveAbi,
129
+ functionName: "approve",
130
+ args: [viem.getAddress(args.token), viem.getAddress(args.spender), args.amount, args.expiration]
131
+ });
132
+ }
133
+ function encodeTrueoTydDeposit(assets, receiver) {
134
+ return viem.encodeFunctionData({
135
+ abi: trueoTydVaultAbi,
136
+ functionName: "deposit",
137
+ args: [assets, viem.getAddress(receiver)]
138
+ });
139
+ }
140
+ function encodeTrueoTydRedeem(shares, receiver, owner) {
141
+ return viem.encodeFunctionData({
142
+ abi: trueoTydVaultAbi,
143
+ functionName: "redeem",
144
+ args: [shares, viem.getAddress(receiver), viem.getAddress(owner)]
145
+ });
146
+ }
147
+ function encodeTrueoMint(paymentTokenAmount) {
148
+ return viem.encodeFunctionData({
149
+ abi: trueoMarketAbi,
150
+ functionName: "mint",
151
+ args: [paymentTokenAmount]
152
+ });
153
+ }
154
+ function encodeTrueoBurn(amount) {
155
+ return viem.encodeFunctionData({
156
+ abi: trueoMarketAbi,
157
+ functionName: "burn",
158
+ args: [amount]
159
+ });
160
+ }
161
+ function encodeTrueoRedeem(amount) {
162
+ return viem.encodeFunctionData({
163
+ abi: trueoMarketAbi,
164
+ functionName: "redeem",
165
+ args: [amount]
166
+ });
167
+ }
168
+ function encodeTrueoAdapterMint(market, assetAmount) {
169
+ return viem.encodeFunctionData({
170
+ abi: trueoAdapterMintAbi,
171
+ functionName: "mint",
172
+ args: [viem.getAddress(market), assetAmount]
173
+ });
174
+ }
175
+ function encodeTrueoAdapterBurn(market, amount) {
176
+ return viem.encodeFunctionData({
177
+ abi: trueoAdapterMintAbi,
178
+ functionName: "burn",
179
+ args: [viem.getAddress(market), amount]
180
+ });
181
+ }
182
+ function encodeTrueoAdapterRedeem(market, amount) {
183
+ return viem.encodeFunctionData({
184
+ abi: trueoAdapterMintAbi,
185
+ functionName: "redeem",
186
+ args: [viem.getAddress(market), amount]
187
+ });
188
+ }
189
+ function encodeTrueoV4ExactInInput(args) {
190
+ const poolKey = {
191
+ currency0: viem.getAddress(args.poolKey.currency0),
192
+ currency1: viem.getAddress(args.poolKey.currency1),
193
+ fee: args.poolKey.fee,
194
+ tickSpacing: args.poolKey.tickSpacing,
195
+ hooks: viem.getAddress(args.poolKey.hooks)
196
+ };
197
+ const settleCurrency = args.zeroForOne ? poolKey.currency0 : poolKey.currency1;
198
+ const takeCurrency = args.zeroForOne ? poolKey.currency1 : poolKey.currency0;
199
+ const swapParams = viem.encodeAbiParameters(
200
+ [
201
+ {
202
+ type: "tuple",
203
+ components: [
204
+ { name: "poolKey", type: "tuple", components: [...poolKeyComponents] },
205
+ { name: "zeroForOne", type: "bool" },
206
+ { name: "amountIn", type: "uint128" },
207
+ { name: "amountOutMinimum", type: "uint128" },
208
+ { name: "hookData", type: "bytes" }
209
+ ]
210
+ }
211
+ ],
212
+ [
213
+ {
214
+ poolKey,
215
+ zeroForOne: args.zeroForOne,
216
+ amountIn: args.amountIn,
217
+ amountOutMinimum: args.amountOutMinimum,
218
+ hookData: "0x"
219
+ }
220
+ ]
221
+ );
222
+ const settleParams = viem.encodeAbiParameters(
223
+ [
224
+ { name: "currency", type: "address" },
225
+ { name: "amount", type: "uint256" },
226
+ { name: "payerIsUser", type: "bool" }
227
+ ],
228
+ [settleCurrency, args.amountIn, true]
229
+ );
230
+ const takeParams = viem.encodeAbiParameters(
231
+ [
232
+ { name: "currency", type: "address" },
233
+ { name: "recipient", type: "address" },
234
+ { name: "amount", type: "uint256" }
235
+ ],
236
+ [takeCurrency, viem.getAddress(args.recipient), 0n]
237
+ );
238
+ const actions = `0x${[V4_ACTION_SWAP_EXACT_IN_SINGLE, V4_ACTION_SETTLE, V4_ACTION_TAKE].map((b) => b.toString(16).padStart(2, "0")).join("")}`;
239
+ return viem.encodeAbiParameters(
240
+ [
241
+ { name: "actions", type: "bytes" },
242
+ { name: "params", type: "bytes[]" }
243
+ ],
244
+ [actions, [swapParams, settleParams, takeParams]]
245
+ );
246
+ }
247
+ function encodeTrueoUniversalRouterExecute(args) {
248
+ return viem.encodeFunctionData({
249
+ abi: trueoUniversalRouterAdapterAbi,
250
+ functionName: "execute",
251
+ args: [args.commands, [...args.inputs], args.deadline]
252
+ });
253
+ }
254
+ function encodeTrueoV4ExactInSwap(args) {
255
+ const commands = `0x${UR_COMMAND_V4_SWAP.toString(16).padStart(2, "0")}`;
256
+ const inputs = [
257
+ encodeTrueoV4ExactInInput({
258
+ poolKey: args.poolKey,
259
+ zeroForOne: args.zeroForOne,
260
+ amountIn: args.amountIn,
261
+ amountOutMinimum: args.amountOutMinimum,
262
+ recipient: args.recipient
263
+ })
264
+ ];
265
+ const data = encodeTrueoUniversalRouterExecute({
266
+ commands,
267
+ inputs,
268
+ deadline: args.deadline
269
+ });
270
+ return { commands, inputs, deadline: args.deadline, data, to: TRUEO_UNIVERSAL_ROUTER_ADAPTER };
271
+ }
272
+ function encodeTrueoCreateOrder(args) {
273
+ return viem.encodeFunctionData({
274
+ abi: trueoOrderManagerStructAbi,
275
+ functionName: "createOrder",
276
+ args: [
277
+ {
278
+ poolKey: {
279
+ currency0: viem.getAddress(args.poolKey.currency0),
280
+ currency1: viem.getAddress(args.poolKey.currency1),
281
+ fee: args.poolKey.fee,
282
+ tickSpacing: args.poolKey.tickSpacing,
283
+ hooks: viem.getAddress(args.poolKey.hooks)
284
+ },
285
+ amountIn: args.amountIn,
286
+ tickLower: args.tickLower,
287
+ tickUpper: args.tickUpper,
288
+ zeroForOne: args.zeroForOne,
289
+ enablePartialFill: args.enablePartialFill
290
+ }
291
+ ]
292
+ });
293
+ }
294
+ function encodeTrueoCancelOrder(args) {
295
+ return viem.encodeFunctionData({
296
+ abi: trueoOrderManagerStructAbi,
297
+ functionName: "cancelOrder",
298
+ args: [
299
+ {
300
+ poolKey: {
301
+ currency0: viem.getAddress(args.poolKey.currency0),
302
+ currency1: viem.getAddress(args.poolKey.currency1),
303
+ fee: args.poolKey.fee,
304
+ tickSpacing: args.poolKey.tickSpacing,
305
+ hooks: viem.getAddress(args.poolKey.hooks)
306
+ },
307
+ orderId: args.orderId,
308
+ amount0Min: args.amount0Min ?? 0n,
309
+ amount1Min: args.amount1Min ?? 0n
310
+ }
311
+ ]
312
+ });
313
+ }
314
+ function trueoPermit2Expiration(nowSec = Math.floor(Date.now() / 1e3)) {
315
+ return nowSec + TRUEO_PERMIT2_APPROVAL_SECONDS;
316
+ }
317
+ function trueoSwapDeadline(nowSec = Math.floor(Date.now() / 1e3)) {
318
+ return BigInt(nowSec + TRUEO_PERMIT2_APPROVAL_SECONDS);
319
+ }
320
+
321
+ // src/protocols/evm/trueo/prices.ts
322
+ var Q96 = 2n ** 96n;
323
+ function trueoImpliedPriceFromSqrtX96(sqrtPriceX96, token0Decimals = TRUEO_OUTCOME_TOKEN_DECIMALS, token1Decimals = TRUEO_TYD_DECIMALS) {
324
+ if (sqrtPriceX96 == null) return null;
325
+ let sqrt;
326
+ try {
327
+ sqrt = typeof sqrtPriceX96 === "bigint" ? sqrtPriceX96 : BigInt(String(sqrtPriceX96));
328
+ } catch {
329
+ return null;
330
+ }
331
+ if (sqrt <= 0n) return null;
332
+ const raw = Number(sqrt) / Number(Q96);
333
+ if (!Number.isFinite(raw) || raw <= 0) return null;
334
+ const price = raw * raw * 10 ** (token0Decimals - token1Decimals);
335
+ return Number.isFinite(price) && price > 0 ? price : null;
336
+ }
337
+ var TRUEO_SANE_IMPLIED_PRICE_MAX = 1.05;
338
+ function trueoIsSaneImpliedPrice(price) {
339
+ return price != null && Number.isFinite(price) && price >= 0 && price <= TRUEO_SANE_IMPLIED_PRICE_MAX;
340
+ }
341
+ function trueoSanitizeBinaryPrices(yes, no) {
342
+ const y = trueoIsSaneImpliedPrice(yes) ? yes : null;
343
+ const n = trueoIsSaneImpliedPrice(no) ? no : null;
344
+ if (y != null && n == null) return { yes: y, no: Math.min(1, Math.max(0, 1 - y)) };
345
+ if (n != null && y == null) return { yes: Math.min(1, Math.max(0, 1 - n)), no: n };
346
+ return { yes: y, no: n };
347
+ }
348
+ function trueoPercentLabel(price) {
349
+ if (!trueoIsSaneImpliedPrice(price)) return null;
350
+ const pct = Math.min(100, Math.max(0, price * 100));
351
+ return `${pct.toFixed(1)}%`;
352
+ }
353
+ function trueoCompactVolumeLabel(size) {
354
+ if (size == null || size === "") return "";
355
+ const n = typeof size === "number" ? size : Number(String(size).replace(/,/g, ""));
356
+ if (!Number.isFinite(n) || n < 0) return "";
357
+ if (n >= 1e6) return `${(n / 1e6).toFixed(n >= 1e7 ? 0 : 1)}M`;
358
+ if (n >= 1e5) return `${(n / 1e3).toFixed(0)}k`;
359
+ if (n >= 1e3) return `${(n / 1e3).toFixed(1)}k`;
360
+ if (n >= 10) return n.toFixed(0);
361
+ if (n >= 1) return n.toFixed(1);
362
+ if (n === 0) return "0";
363
+ return n.toFixed(2);
364
+ }
365
+ function trueoExpiresAtIso(endOfTrading) {
366
+ if (!Number.isFinite(endOfTrading) || endOfTrading <= 0) return null;
367
+ return new Date(endOfTrading * 1e3).toISOString();
368
+ }
369
+ function trueoExpiresAtLabel(endOfTrading) {
370
+ if (!Number.isFinite(endOfTrading) || endOfTrading <= 0) return null;
371
+ const d = new Date(endOfTrading * 1e3);
372
+ const y = d.getUTCFullYear();
373
+ const m = String(d.getUTCMonth() + 1).padStart(2, "0");
374
+ const day = String(d.getUTCDate()).padStart(2, "0");
375
+ const hh = String(d.getUTCHours()).padStart(2, "0");
376
+ const mm = String(d.getUTCMinutes()).padStart(2, "0");
377
+ return `${y}-${m}-${day} ${hh}:${mm} UTC`;
378
+ }
379
+ var UTC_MONTHS = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
380
+ function trueoTradingDeadlineLabel(endOfTrading) {
381
+ if (!Number.isFinite(endOfTrading) || endOfTrading <= 0) return null;
382
+ const d = new Date(endOfTrading * 1e3);
383
+ const day = d.getUTCDate();
384
+ const mon = UTC_MONTHS[d.getUTCMonth()];
385
+ const y = d.getUTCFullYear();
386
+ const hh = String(d.getUTCHours()).padStart(2, "0");
387
+ const mm = String(d.getUTCMinutes()).padStart(2, "0");
388
+ return `${day} ${mon} ${y}, ${hh}:${mm} UTC`;
389
+ }
390
+ function trueoTimeUntilTradingEndsLabel(endOfTrading, nowSec = Math.floor(Date.now() / 1e3)) {
391
+ if (!Number.isFinite(endOfTrading) || endOfTrading <= 0) return null;
392
+ const sec = Math.floor(endOfTrading) - nowSec;
393
+ if (sec <= 0) return "ended";
394
+ const days = Math.floor(sec / 86400);
395
+ const hours = Math.floor(sec % 86400 / 3600);
396
+ if (days >= 60) {
397
+ const months = Math.max(1, Math.round(days / 30));
398
+ return `in ${months} month${months === 1 ? "" : "s"}`;
399
+ }
400
+ if (days >= 2) return `in ${days} days`;
401
+ if (days === 1) return hours > 0 ? `in 1 day ${hours}h` : "in 1 day";
402
+ if (hours >= 2) return `in ${hours} hours`;
403
+ const mins = Math.max(1, Math.floor(sec / 60));
404
+ return `in ${mins} min`;
405
+ }
406
+
407
+ // src/protocols/evm/trueo/marketScope.ts
408
+ var TRUEO_RECENT_MARKET_WINDOW_SECONDS = 14 * 24 * 60 * 60;
409
+ function trueoFinishedAtSec(row, nowSec) {
410
+ if (row.endOfTrading > 0 && nowSec >= row.endOfTrading) return row.endOfTrading;
411
+ if (row.statusUpdatedAt?.trim()) {
412
+ const ms = Date.parse(row.statusUpdatedAt);
413
+ if (Number.isFinite(ms) && ms <= nowSec * 1e3) return Math.floor(ms / 1e3);
414
+ }
415
+ return null;
416
+ }
417
+ function isTrueoMarketLiveOrRecent(row, nowSec = Math.floor(Date.now() / 1e3), recentWindowSec = TRUEO_RECENT_MARKET_WINDOW_SECONDS) {
418
+ if (row.endOfTrading > 0 && nowSec < row.endOfTrading) return true;
419
+ const status = Number(row.status);
420
+ if (status === 0 && row.endOfTrading <= 0) return true;
421
+ const finishedAt = trueoFinishedAtSec(row, nowSec);
422
+ if (finishedAt == null) return false;
423
+ return nowSec - finishedAt <= recentWindowSec;
424
+ }
425
+ function applyTrueoMarketSearchScope(rows, args) {
426
+ if (args?.includeAll === true) return rows;
427
+ return rows.filter((row) => isTrueoMarketLiveOrRecent(row, args?.nowSec));
428
+ }
429
+ function isTrueoMarketTradingOpen(row, nowSec = Math.floor(Date.now() / 1e3)) {
430
+ const status = Number(row.status);
431
+ if (status !== 0) return false;
432
+ if (row.endOfTrading > 0 && nowSec >= row.endOfTrading) return false;
433
+ return true;
434
+ }
435
+ function preferOpenTrueoTitleMatches(rows, args) {
436
+ if (args?.includeAll === true || rows.length === 0) return rows;
437
+ const open = rows.filter((row) => isTrueoMarketTradingOpen(row, args?.nowSec));
438
+ return open.length > 0 ? open : rows;
439
+ }
440
+ function trueoSearchScopeNote(includeAll) {
441
+ return includeAll ? "Includes closed and resolved markets." : "Live and recently finished only (last 14 days). Set includeAll to include older closed markets.";
442
+ }
443
+
444
+ // src/protocols/evm/trueo/marketApi.ts
445
+ function trueoHeaders() {
446
+ return { Accept: "application/json" };
447
+ }
448
+ async function trueoJsonFetch(path, opts) {
449
+ const url = path.startsWith("http") ? path : `${TRUEO_API_ORIGIN}${path}`;
450
+ const res = await fetch(url, { headers: trueoHeaders(), signal: opts?.signal });
451
+ if (!res.ok) {
452
+ throw new Error(`Trueo API ${res.status} for ${path}`);
453
+ }
454
+ return await res.json();
455
+ }
456
+ function asRecord(value) {
457
+ return value && typeof value === "object" && !Array.isArray(value) ? value : null;
458
+ }
459
+ function asString(value, fallback = "") {
460
+ return value == null ? fallback : String(value);
461
+ }
462
+ function asNumber(value, fallback = 0) {
463
+ const n = typeof value === "number" ? value : Number(value);
464
+ return Number.isFinite(n) ? n : fallback;
465
+ }
466
+ function asNumberOrNull(value) {
467
+ if (value == null || value === "") return null;
468
+ const n = typeof value === "number" ? value : Number(value);
469
+ return Number.isFinite(n) ? n : null;
470
+ }
471
+ function asStringArray(value) {
472
+ if (!Array.isArray(value)) return [];
473
+ return value.map((v) => String(v)).filter(Boolean);
474
+ }
475
+ function normalizeTrueoMarketRow(raw) {
476
+ const r = asRecord(raw) ?? {};
477
+ const address = asString(r.address).toLowerCase();
478
+ const endOfTrading = asNumber(r.endOfTrading, 0);
479
+ const yesSqrt = r.yesPoolSqrtPriceX96 == null ? null : asString(r.yesPoolSqrtPriceX96);
480
+ const noSqrt = r.noPoolSqrtPriceX96 == null ? null : asString(r.noPoolSqrtPriceX96);
481
+ const { yes: yesPrice, no: noPrice } = trueoSanitizeBinaryPrices(
482
+ trueoImpliedPriceFromSqrtX96(yesSqrt),
483
+ trueoImpliedPriceFromSqrtX96(noSqrt)
484
+ );
485
+ return {
486
+ address,
487
+ question: asString(r.question),
488
+ rules: asString(r.rules),
489
+ source: asString(r.source),
490
+ categories: asStringArray(r.categories),
491
+ size: asString(r.size, "0"),
492
+ tvl: asNumberOrNull(r.tvl),
493
+ yesTokenAddress: asString(r.yesTokenAddress).toLowerCase(),
494
+ noTokenAddress: asString(r.noTokenAddress).toLowerCase(),
495
+ yesPoolAddress: asString(r.yesPoolAddress).toLowerCase(),
496
+ noPoolAddress: asString(r.noPoolAddress).toLowerCase(),
497
+ paymentTokenAddress: asString(r.paymentTokenAddress).toLowerCase(),
498
+ paymentTokenSymbol: asString(r.paymentTokenSymbol, "TYD"),
499
+ paymentTokenDecimals: asNumber(r.paymentTokenDecimals, 6),
500
+ endOfTrading,
501
+ status: asNumber(r.status, 0),
502
+ outcome: asNumber(r.outcome, 0),
503
+ statusUpdatedAt: r.statusUpdatedAt == null || r.statusUpdatedAt === "" ? null : asString(r.statusUpdatedAt),
504
+ imageUrl: r.imageUrl == null ? null : asString(r.imageUrl),
505
+ yesPoolTick: asNumberOrNull(r.yesPoolTick),
506
+ noPoolTick: asNumberOrNull(r.noPoolTick),
507
+ yesPoolSqrtPriceX96: yesSqrt,
508
+ noPoolSqrtPriceX96: noSqrt,
509
+ yesPrice,
510
+ noPrice,
511
+ yesPriceLabel: trueoPercentLabel(yesPrice),
512
+ noPriceLabel: trueoPercentLabel(noPrice),
513
+ expiresAt: trueoExpiresAtIso(endOfTrading),
514
+ expiresAtLabel: trueoExpiresAtLabel(endOfTrading),
515
+ chainId: TRUEO_BASE_CHAIN_ID,
516
+ network: asString(r.network, TRUEO_NETWORK)
517
+ };
518
+ }
519
+ var TRUEO_QUERY_STOPWORDS = /* @__PURE__ */ new Set([
520
+ "the",
521
+ "for",
522
+ "any",
523
+ "all",
524
+ "and",
525
+ "search",
526
+ "find",
527
+ "show",
528
+ "list",
529
+ "market",
530
+ "markets",
531
+ "prediction",
532
+ "live",
533
+ "recent",
534
+ "trending",
535
+ "trueo",
536
+ "topic",
537
+ "about"
538
+ ]);
539
+ function trueoQueryTokens(query) {
540
+ const seen = /* @__PURE__ */ new Set();
541
+ const out = [];
542
+ for (const raw of query.toLowerCase().split(/[^a-z0-9]+/)) {
543
+ const t = raw.trim();
544
+ if (t.length < 3 || TRUEO_QUERY_STOPWORDS.has(t) || seen.has(t)) continue;
545
+ seen.add(t);
546
+ out.push(t);
547
+ }
548
+ return out;
549
+ }
550
+ function filterTrueoMarkets(rows, args) {
551
+ const q = args.query?.trim().toLowerCase() ?? "";
552
+ const tokens = q ? trueoQueryTokens(q) : [];
553
+ const category = args.category?.trim().toLowerCase() ?? "";
554
+ return rows.filter((row) => {
555
+ if (category) {
556
+ const hit = row.categories.some((c) => c.toLowerCase() === category || c.toLowerCase().includes(category));
557
+ if (!hit) return false;
558
+ }
559
+ if (!q) return true;
560
+ const hay = [
561
+ row.question,
562
+ row.rules,
563
+ row.source,
564
+ row.address,
565
+ row.yesTokenAddress,
566
+ row.noTokenAddress,
567
+ ...row.categories
568
+ ].join(" ").toLowerCase();
569
+ if (hay.includes(q)) return true;
570
+ return tokens.some((t) => hay.includes(t));
571
+ });
572
+ }
573
+ async function fetchTrueoCategories(opts) {
574
+ const raw = await trueoJsonFetch(trueoMarketApiPath("categories"), opts);
575
+ if (!Array.isArray(raw)) return [];
576
+ return raw.map((item) => {
577
+ const r = asRecord(item);
578
+ if (!r) return null;
579
+ const name = asString(r.name).trim();
580
+ if (!name) return null;
581
+ return { id: asNumber(r.id, 0), name };
582
+ }).filter((c) => c != null);
583
+ }
584
+ var TRUEO_TRENDING_MAX_LIMIT = 10;
585
+ var TRUEO_MARKET_PAGE_SIZE = 10;
586
+ function trueoSearchFetchLimit(requested, includeAll) {
587
+ const cap = 100;
588
+ if (includeAll) return Math.min(requested, cap);
589
+ return Math.min(Math.max(requested * 4, 40), cap);
590
+ }
591
+ async function fetchTrueoTrending(args) {
592
+ const requested = Math.min(Math.max(args?.limit ?? 20, 1), TRUEO_TRENDING_MAX_LIMIT);
593
+ const includeAll = args?.includeAll === true;
594
+ const raw = await trueoJsonFetch(
595
+ `${trueoMarketApiPath(`${TRUEO_NETWORK}/trending`)}?limit=${requested}`,
596
+ args?.opts
597
+ );
598
+ if (!Array.isArray(raw)) return [];
599
+ const rows = applyTrueoMarketSearchScope(raw.map(normalizeTrueoMarketRow), { includeAll });
600
+ return rows.slice(0, requested);
601
+ }
602
+ var TRUEO_TITLE_SEARCH_PAGE_SIZE = 100;
603
+ var TRUEO_TITLE_SEARCH_MAX_PAGES = 16;
604
+ async function searchTrueoMarketsPage(args) {
605
+ const requested = Math.min(Math.max(args.limit ?? TRUEO_MARKET_PAGE_SIZE, 1), 100);
606
+ const includeAll = args.includeAll === true;
607
+ const titleQuery = Boolean(args.query?.trim());
608
+ const pageSize = titleQuery ? TRUEO_TITLE_SEARCH_PAGE_SIZE : trueoSearchFetchLimit(requested, includeAll);
609
+ const maxPages = titleQuery ? TRUEO_TITLE_SEARCH_MAX_PAGES : 3;
610
+ let offset = Math.max(args.offset ?? 0, 0);
611
+ const exclude = new Set((args.excludeAddresses ?? []).map((a) => a.toLowerCase()));
612
+ const collected = [];
613
+ let apiExhausted = false;
614
+ for (let page = 0; page < maxPages && collected.length < requested; page++) {
615
+ const params = new URLSearchParams();
616
+ params.set("limit", String(pageSize));
617
+ params.set("offset", String(offset));
618
+ if (args.category?.trim()) params.set("category", args.category.trim());
619
+ const raw = await trueoJsonFetch(
620
+ `${trueoMarketApiPath(TRUEO_NETWORK)}?${params.toString()}`,
621
+ args.opts
622
+ );
623
+ const pageRows = Array.isArray(raw) ? raw.map(normalizeTrueoMarketRow) : [];
624
+ const scoped = applyTrueoMarketSearchScope(
625
+ filterTrueoMarkets(pageRows, { query: args.query, category: args.category }),
626
+ { includeAll }
627
+ );
628
+ let filled = false;
629
+ for (const row of scoped) {
630
+ if (exclude.has(row.address)) continue;
631
+ exclude.add(row.address);
632
+ collected.push(row);
633
+ const enough = titleQuery && !includeAll ? collected.filter((r) => isTrueoMarketTradingOpen(r)).length >= requested : collected.length >= requested;
634
+ if (enough) {
635
+ filled = true;
636
+ break;
637
+ }
638
+ }
639
+ if (filled) break;
640
+ offset += pageRows.length;
641
+ if (pageRows.length < pageSize) {
642
+ apiExhausted = true;
643
+ break;
644
+ }
645
+ }
646
+ const ranked = titleQuery ? preferOpenTrueoTitleMatches(collected, { includeAll }) : collected;
647
+ const markets = ranked.slice(0, requested);
648
+ return {
649
+ markets,
650
+ hasMore: !apiExhausted,
651
+ nextOffset: offset
652
+ };
653
+ }
654
+ async function searchTrueoMarkets(args) {
655
+ return (await searchTrueoMarketsPage(args)).markets;
656
+ }
657
+ function trueoListUsesTrending(args) {
658
+ if (args.query?.trim() || args.category?.trim()) return false;
659
+ const offset = Math.max(args.offset ?? 0, 0);
660
+ return args.trending === true || offset === 0 && args.trending !== false;
661
+ }
662
+ async function listTrueoMarketsPage(args) {
663
+ const offset = Math.max(args.offset ?? 0, 0);
664
+ const includeAll = args.includeAll === true;
665
+ const useTrending = trueoListUsesTrending(args);
666
+ if (useTrending) {
667
+ const markets = await fetchTrueoTrending({ limit: TRUEO_TRENDING_MAX_LIMIT, includeAll, opts: args.opts });
668
+ if (includeAll || markets.length >= TRUEO_TRENDING_MAX_LIMIT) {
669
+ return { markets, hasMore: true, nextOffset: 0 };
670
+ }
671
+ const fill = await searchTrueoMarketsPage({
672
+ limit: TRUEO_TRENDING_MAX_LIMIT - markets.length,
673
+ includeAll,
674
+ excludeAddresses: [...args.excludeAddresses ?? [], ...markets.map((m) => m.address)],
675
+ opts: args.opts
676
+ });
677
+ return {
678
+ markets: [...markets, ...fill.markets],
679
+ hasMore: fill.hasMore,
680
+ nextOffset: fill.nextOffset
681
+ };
682
+ }
683
+ return searchTrueoMarketsPage({
684
+ query: args.query,
685
+ category: args.category,
686
+ limit: TRUEO_MARKET_PAGE_SIZE,
687
+ offset,
688
+ includeAll,
689
+ excludeAddresses: args.excludeAddresses,
690
+ opts: args.opts
691
+ });
692
+ }
693
+ async function fetchTrueoMarket(args) {
694
+ const address = viem.getAddress(args.marketAddress).toLowerCase();
695
+ const raw = await trueoJsonFetch(trueoMarketApiPath(`${TRUEO_NETWORK}/${address}`), args.opts);
696
+ return normalizeTrueoMarketRow(raw);
697
+ }
698
+ var TRUEO_CHANCE_SERIES_RESOLUTION = "3600";
699
+ var TRUEO_CHANCE_SERIES_LOOKBACK_SECONDS = 14 * 24 * 60 * 60;
700
+ var TRUEO_OHLC_CALENDAR_ALIASES = /* @__PURE__ */ new Set(["1h", "1d", "1w", "all", "hour", "day", "week"]);
701
+ function normalizeTrueoOhlcResolution(raw) {
702
+ const v = raw?.trim() ?? "";
703
+ if (!v || TRUEO_OHLC_CALENDAR_ALIASES.has(v.toLowerCase())) {
704
+ return TRUEO_CHANCE_SERIES_RESOLUTION;
705
+ }
706
+ return v;
707
+ }
708
+ async function fetchTrueoOhlc(args) {
709
+ const poolId = args.poolId.startsWith("0x") ? args.poolId.toLowerCase() : args.poolId;
710
+ const resolution = normalizeTrueoOhlcResolution(args.resolution);
711
+ const raw = await trueoJsonFetch(
712
+ `${trueoMarketApiPath(`${TRUEO_NETWORK}/${poolId}/ohlc`)}?from=${Math.floor(args.from)}&to=${Math.floor(args.to)}&resolution=${encodeURIComponent(resolution)}`,
713
+ args.opts
714
+ );
715
+ if (!Array.isArray(raw)) return [];
716
+ return raw.map((item) => {
717
+ const r = asRecord(item);
718
+ if (!r) return null;
719
+ return {
720
+ timestamp: asNumber(r.timestamp, 0),
721
+ open: asNumber(r.open, 0),
722
+ high: asNumber(r.high, 0),
723
+ low: asNumber(r.low, 0),
724
+ close: asNumber(r.close, 0)
725
+ };
726
+ }).filter((b) => b != null && b.timestamp > 0);
727
+ }
728
+ async function fetchTrueoTransactions(args) {
729
+ const address = viem.getAddress(args.marketAddress).toLowerCase();
730
+ const limit = Math.min(Math.max(args.limit ?? 20, 1), 100);
731
+ const raw = await trueoJsonFetch(
732
+ `${trueoMarketApiPath("transactions")}?marketAddress=${address}&limit=${limit}`,
733
+ args.opts
734
+ );
735
+ return Array.isArray(raw) ? raw : [];
736
+ }
737
+ async function trueoFetchCategoriesSummary() {
738
+ const categories = await fetchTrueoCategories();
739
+ return { categories, chainId: TRUEO_BASE_CHAIN_ID };
740
+ }
741
+ async function trueoFetchTrendingSummary(input = {}) {
742
+ const includeAll = input.includeAll === true;
743
+ const markets = await fetchTrueoTrending({ limit: input.limit, includeAll });
744
+ return {
745
+ markets,
746
+ hasMore: true,
747
+ nextOffset: 0,
748
+ notes: `Trueo trending on Base (max ${TRUEO_TRENDING_MAX_LIMIT}; API does not page trending). More: ctm_trueo_search_markets with offset=0, skip listed addresses. ${trueoSearchScopeNote(includeAll)}`
749
+ };
750
+ }
751
+ async function trueoSearchMarketsSummary(input) {
752
+ const includeAll = input.includeAll === true;
753
+ const page = await searchTrueoMarketsPage({ ...input, includeAll });
754
+ const q = input.query?.trim() ?? "";
755
+ let notes = `Trueo search on Base (page ${TRUEO_MARKET_PAGE_SIZE}). ${page.hasMore ? `More: same tool with offset=${page.nextOffset}.` : "End of results."} ${trueoSearchScopeNote(includeAll)}`;
756
+ if (q && page.markets.length === 0) {
757
+ notes = `No live or recent title match for ${JSON.stringify(q)} after scanning the catalog (vendor search text is ignored). Do not list trending unless the operator asked.`;
758
+ }
759
+ return {
760
+ markets: page.markets,
761
+ hasMore: page.hasMore,
762
+ nextOffset: page.nextOffset,
763
+ notes
764
+ };
765
+ }
766
+ async function trueoFetchMarketSummary(input) {
767
+ return fetchTrueoMarket({ marketAddress: input.marketAddress });
768
+ }
769
+ async function fetchTrueoChanceSeries(args) {
770
+ const to = Math.floor(Date.now() / 1e3);
771
+ const lookback = Math.max(3600, args.lookbackSeconds ?? TRUEO_CHANCE_SERIES_LOOKBACK_SECONDS);
772
+ const bars = await fetchTrueoOhlc({
773
+ poolId: args.poolId,
774
+ from: to - lookback,
775
+ to,
776
+ resolution: TRUEO_CHANCE_SERIES_RESOLUTION,
777
+ opts: args.opts
778
+ });
779
+ return bars.filter((b) => trueoIsSaneImpliedPrice(b.close));
780
+ }
781
+ async function trueoFetchChanceSeriesSummary(input) {
782
+ const resolution = normalizeTrueoOhlcResolution(input.resolution);
783
+ const to = input.to ?? Math.floor(Date.now() / 1e3);
784
+ const from = input.from ?? to - Math.max(1, input.lookbackDays ?? TRUEO_CHANCE_SERIES_LOOKBACK_SECONDS / 86400) * 86400;
785
+ const bars = await fetchTrueoOhlc({
786
+ poolId: input.poolId,
787
+ from,
788
+ to,
789
+ resolution
790
+ });
791
+ return {
792
+ poolId: input.poolId,
793
+ bars,
794
+ from,
795
+ to,
796
+ resolution,
797
+ notes: "Chance samples (not candlesticks). resolution is seconds; default 3600 (hourly). 1H/1D/1W/All coerce to hourly."
798
+ };
799
+ }
800
+ var TRUEO_BET_CLOSE_ERROR = "Market closes within 5 minutes.";
801
+ var TRUEO_BET_EXPIRED_ERROR = "Market expired. Cannot Get Sig or Execute.";
802
+ function trueoMarketStatusLabel(row, nowSec = Math.floor(Date.now() / 1e3)) {
803
+ const status = Number(row.status);
804
+ if (status === 7) return "resolved";
805
+ if (status >= 4) return "closed";
806
+ if (status >= 1) return "resolving";
807
+ if (row.endOfTrading > 0 && nowSec >= row.endOfTrading) return "closed";
808
+ return "open";
809
+ }
810
+ function trueoTradingEndsCopy(row, nowSec = Math.floor(Date.now() / 1e3)) {
811
+ const when = trueoTradingDeadlineLabel(row.endOfTrading);
812
+ if (!when) {
813
+ return trueoMarketStatusLabel(row, nowSec) === "open" ? "Trading end unknown" : "Trading ended";
814
+ }
815
+ const remain = trueoTimeUntilTradingEndsLabel(row.endOfTrading, nowSec);
816
+ return remain && remain !== "ended" ? `Trading ends ${when} \xB7 ${remain}` : `Trading ended ${when}`;
817
+ }
818
+ function trueoResolvedSide(outcome) {
819
+ if (outcome === 1) return "yes";
820
+ if (outcome === 2) return "no";
821
+ return null;
822
+ }
823
+ function statusUpdatedAtLabel(raw) {
824
+ if (!raw?.trim()) return null;
825
+ const ms = Date.parse(raw);
826
+ if (!Number.isFinite(ms)) return null;
827
+ return trueoTradingDeadlineLabel(Math.floor(ms / 1e3));
828
+ }
829
+ function trueoResolutionCopy(row, nowSec = Math.floor(Date.now() / 1e3)) {
830
+ const status = Number(row.status);
831
+ const when = statusUpdatedAtLabel(row.statusUpdatedAt);
832
+ const side = trueoResolvedSide(row.outcome);
833
+ const sideWord = side === "yes" ? "Yes" : side === "no" ? "No" : null;
834
+ if (status === 7) {
835
+ const who = sideWord ?? "unknown outcome";
836
+ return when ? `Resolved ${who} \xB7 ${when}` : `Resolved ${who}`;
837
+ }
838
+ if (status >= 1 && status < 4) {
839
+ return when ? `This market is being resolved \xB7 since ${when}` : "This market is being resolved";
840
+ }
841
+ if (status >= 4) {
842
+ if (sideWord) return when ? `Closed ${sideWord} \xB7 ${when}` : `Closed ${sideWord}`;
843
+ return when ? `Closed without a Yes/No result \xB7 ${when}` : "Closed without a Yes/No result";
844
+ }
845
+ if (row.endOfTrading > 0 && nowSec >= row.endOfTrading) {
846
+ return "This market is being resolved";
847
+ }
848
+ return null;
849
+ }
850
+ function isTrueoBetAction(action) {
851
+ return TRUEO_BET_ACTIONS.includes(action);
852
+ }
853
+ function trueoMarketVotingOpen(row, nowSec = Math.floor(Date.now() / 1e3)) {
854
+ return trueoBetCreateBlockedReason(row, nowSec) == null;
855
+ }
856
+ function trueoBetCreateBlockedReason(row, nowSec = Math.floor(Date.now() / 1e3)) {
857
+ const label = trueoMarketStatusLabel(row, nowSec);
858
+ if (label !== "open") return TRUEO_BET_CLOSE_ERROR;
859
+ if (row.endOfTrading > 0 && nowSec + TRUEO_BET_CLOSE_BUFFER_SECONDS >= row.endOfTrading) {
860
+ return TRUEO_BET_CLOSE_ERROR;
861
+ }
862
+ return null;
863
+ }
864
+ function trueoBetExecuteBlockedReason(row, nowSec = Math.floor(Date.now() / 1e3)) {
865
+ const label = trueoMarketStatusLabel(row, nowSec);
866
+ if (label === "resolved" || label === "closed") return TRUEO_BET_EXPIRED_ERROR;
867
+ if (row.endOfTrading > 0 && nowSec >= row.endOfTrading) return TRUEO_BET_EXPIRED_ERROR;
868
+ return null;
869
+ }
870
+ function assertTrueoBetCanCreate(row, nowSec = Math.floor(Date.now() / 1e3)) {
871
+ const reason = trueoBetCreateBlockedReason(row, nowSec);
872
+ if (reason) throw new Error(reason);
873
+ }
874
+ function assertTrueoBetCanExecute(row, nowSec = Math.floor(Date.now() / 1e3)) {
875
+ const reason = trueoBetExecuteBlockedReason(row, nowSec);
876
+ if (reason) throw new Error(reason);
877
+ }
878
+ async function assertTrueoBetStillOpen(marketAddress) {
879
+ const row = await fetchTrueoMarket({ marketAddress: viem.getAddress(marketAddress) });
880
+ assertTrueoBetCanExecute(row);
881
+ return row;
882
+ }
883
+ function buildTrueoBetExtraJson(args) {
884
+ return {
885
+ protocolId: "trueo",
886
+ trueoAction: args.action,
887
+ marketAddress: viem.getAddress(args.marketAddress),
888
+ endOfTrading: args.endOfTrading
889
+ };
890
+ }
891
+ function parseTrueoBetExtraJson(raw) {
892
+ let obj = null;
893
+ if (typeof raw === "string" && raw.trim()) {
894
+ try {
895
+ const parsed = JSON.parse(raw);
896
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
897
+ obj = parsed;
898
+ }
899
+ } catch {
900
+ return null;
901
+ }
902
+ } else if (raw && typeof raw === "object" && !Array.isArray(raw)) {
903
+ obj = raw;
904
+ }
905
+ if (!obj) return null;
906
+ if (obj.protocolId !== "trueo") return null;
907
+ const action = String(obj.trueoAction ?? "");
908
+ if (!isTrueoBetAction(action)) return null;
909
+ const marketAddress = String(obj.marketAddress ?? "").trim();
910
+ if (!marketAddress) return null;
911
+ const endOfTrading = Number(obj.endOfTrading ?? 0);
912
+ return {
913
+ protocolId: "trueo",
914
+ trueoAction: action,
915
+ marketAddress,
916
+ endOfTrading: Number.isFinite(endOfTrading) ? endOfTrading : 0
917
+ };
918
+ }
919
+ function extraJsonFromSignRequest(detail) {
920
+ return detail?.ExtraJSON ?? detail?.extraJSON ?? null;
921
+ }
922
+ function defiEvmTransport(rpcUrl, opts) {
923
+ const url = rpcUrl.trim();
924
+ return viem.http(url, opts);
925
+ }
926
+
927
+ // src/protocols/evm/trueo/orderbook.ts
928
+ function publicClient(rpcUrl, chainId) {
929
+ const chain = viem.defineChain({
930
+ id: chainId,
931
+ name: "Base",
932
+ nativeCurrency: { decimals: 18, name: "Ether", symbol: "ETH" },
933
+ rpcUrls: { default: { http: [rpcUrl] } }
934
+ });
935
+ return viem.createPublicClient({ chain, transport: defiEvmTransport(rpcUrl) });
936
+ }
937
+ async function readTrueoPoolKeys(args) {
938
+ const client2 = publicClient(args.rpcUrl, TRUEO_BASE_CHAIN_ID);
939
+ try {
940
+ const [yes, no] = await client2.readContract({
941
+ address: viem.getAddress(args.marketAddress),
942
+ abi: trueoMarketV2Abi,
943
+ functionName: "getPoolKeys"
944
+ });
945
+ return {
946
+ yes: {
947
+ currency0: yes.currency0,
948
+ currency1: yes.currency1,
949
+ fee: Number(yes.fee),
950
+ tickSpacing: Number(yes.tickSpacing),
951
+ hooks: yes.hooks
952
+ },
953
+ no: {
954
+ currency0: no.currency0,
955
+ currency1: no.currency1,
956
+ fee: Number(no.fee),
957
+ tickSpacing: Number(no.tickSpacing),
958
+ hooks: no.hooks
959
+ }
960
+ };
961
+ } catch {
962
+ return null;
963
+ }
964
+ }
965
+ async function probePendingOrders(args) {
966
+ const client2 = publicClient(args.rpcUrl, TRUEO_BASE_CHAIN_ID);
967
+ const levels = [];
968
+ const ids = [1, 2, 3, 4, 5, 6, 7, 8];
969
+ const reads = await Promise.all(
970
+ ids.map(async (orderId) => {
971
+ try {
972
+ const order = await client2.readContract({
973
+ address: TRUEO_ORDER_MANAGER,
974
+ abi: trueoOrderManagerAbi,
975
+ functionName: "pendingOrder",
976
+ args: [args.poolId, orderId]
977
+ });
978
+ const [owner, zeroForOne, tickLower, , liquidity] = order;
979
+ if (!owner || owner === "0x0000000000000000000000000000000000000000") return null;
980
+ if (liquidity === 0n) return null;
981
+ return {
982
+ tick: Number(tickLower),
983
+ price: null,
984
+ orderId,
985
+ owner,
986
+ zeroForOne: Boolean(zeroForOne)
987
+ };
988
+ } catch {
989
+ return null;
990
+ }
991
+ })
992
+ );
993
+ for (const row of reads) {
994
+ if (row) levels.push(row);
995
+ }
996
+ return levels;
997
+ }
998
+ function recentTradesFromApi(raw, _side, poolId) {
999
+ return raw.map((item) => {
1000
+ if (!item || typeof item !== "object") return null;
1001
+ const r = item;
1002
+ const swap = r.v4PoolSwapData && typeof r.v4PoolSwapData === "object" ? r.v4PoolSwapData : null;
1003
+ const tradePool = swap ? String(swap.poolId ?? "").toLowerCase() : "";
1004
+ if (tradePool && tradePool !== poolId.toLowerCase()) return null;
1005
+ return {
1006
+ timestamp: r.timestamp == null ? null : String(r.timestamp),
1007
+ price: swap && typeof swap.price === "number" ? swap.price : null,
1008
+ usdValue: r.usdValue == null ? null : String(r.usdValue),
1009
+ poolId: tradePool || null
1010
+ };
1011
+ }).filter((t) => t != null).slice(0, 12);
1012
+ }
1013
+ async function fetchTrueoOrderbook(args) {
1014
+ const market = await fetchTrueoMarket({ marketAddress: args.marketAddress });
1015
+ const side = args.side === "no" ? "no" : "yes";
1016
+ const poolId = side === "yes" ? market.yesPoolAddress : market.noPoolAddress;
1017
+ const impliedPrice = side === "yes" ? market.yesPrice : market.noPrice;
1018
+ const currentTick = side === "yes" ? market.yesPoolTick : market.noPoolTick;
1019
+ const txs = await fetchTrueoTransactions({ marketAddress: market.address, limit: 20 }).catch(() => []);
1020
+ let levels = [];
1021
+ if (args.rpcUrl && poolId.startsWith("0x") && poolId.length === 66) {
1022
+ levels = await probePendingOrders({ rpcUrl: args.rpcUrl, poolId });
1023
+ }
1024
+ return {
1025
+ marketAddress: market.address,
1026
+ side,
1027
+ poolId,
1028
+ currentTick,
1029
+ impliedPrice,
1030
+ impliedPriceLabel: side === "yes" ? market.yesPriceLabel : market.noPriceLabel,
1031
+ levels,
1032
+ recentTrades: recentTradesFromApi(txs, side, poolId),
1033
+ notes: levels.length ? "On-chain OrderManager pending orders plus recent pool trades." : "Depth from live tick / implied price and recent pool trades. Pending OrderManager rows are included when rpcUrl can read them."
1034
+ };
1035
+ }
1036
+ async function trueoFetchOrderbookSummary(input) {
1037
+ return fetchTrueoOrderbook(input);
1038
+ }
1039
+ function outcomeTokensFromMarkets(markets) {
1040
+ const out = /* @__PURE__ */ new Set();
1041
+ for (const m of markets) {
1042
+ if (m.yesTokenAddress) out.add(m.yesTokenAddress.toLowerCase());
1043
+ if (m.noTokenAddress) out.add(m.noTokenAddress.toLowerCase());
1044
+ }
1045
+ return [...out];
1046
+ }
1047
+ function isTrueoOutcomeTokenLabel(symbol, name) {
1048
+ const s = (symbol ?? "").trim().toUpperCase();
1049
+ if (s === "YES" || s === "NO") return true;
1050
+ const n = (name ?? "").trim().toLowerCase();
1051
+ return n.startsWith("trueo yes") || n.startsWith("trueo no");
1052
+ }
1053
+ function clipQuestion(question) {
1054
+ const t = (question ?? "").trim();
1055
+ if (!t) return "Trueo market";
1056
+ return t.length <= 48 ? t : `${t.slice(0, 45).trim()}\u2026`;
1057
+ }
1058
+ function outcomeToken(address, kind, question) {
1059
+ const label = clipQuestion(question);
1060
+ const side = kind === "no" ? "No" : "Yes";
1061
+ return {
1062
+ address: viem.getAddress(address),
1063
+ name: `Trueo ${side} \u2014 ${label}`,
1064
+ symbol: kind === "no" ? "NO" : "YES",
1065
+ decimals: TRUEO_OUTCOME_TOKEN_DECIMALS,
1066
+ kind
1067
+ };
1068
+ }
1069
+ function suggestTrueoTokensToAdd(args) {
1070
+ const tyd = {
1071
+ address: TRUEO_TYD,
1072
+ name: "True Yield Dollar",
1073
+ symbol: "TYD",
1074
+ decimals: TRUEO_TYD_DECIMALS,
1075
+ kind: "tyd"
1076
+ };
1077
+ const usdc = {
1078
+ address: TRUEO_USDC,
1079
+ name: "USD Coin",
1080
+ symbol: "USDC",
1081
+ decimals: 6,
1082
+ kind: "usdc"
1083
+ };
1084
+ if (args.action === "wrapTyd") return [tyd];
1085
+ if (args.action === "unwrapTyd") return [usdc];
1086
+ if (!args.market) return [];
1087
+ try {
1088
+ const yes = outcomeToken(args.market.yesTokenAddress, "yes", args.market.question);
1089
+ const no = outcomeToken(args.market.noTokenAddress, "no", args.market.question);
1090
+ switch (args.action) {
1091
+ case "swap":
1092
+ case "createOrder":
1093
+ return [args.side === "no" ? no : yes];
1094
+ case "mint":
1095
+ return [yes, no];
1096
+ case "burn":
1097
+ case "redeem":
1098
+ return [tyd];
1099
+ default:
1100
+ return [];
1101
+ }
1102
+ } catch {
1103
+ return [];
1104
+ }
1105
+ }
1106
+
1107
+ // src/protocols/evm/trueo/predictionSearch.ts
1108
+ var PREDICTION_MARKET_V1_KIND = "continuum/prediction-market/v1";
1109
+ function trueoMarketToPredictionRow(row) {
1110
+ const status = trueoMarketStatusLabel(row);
1111
+ return {
1112
+ venue: "trueo",
1113
+ venueMarketId: row.address,
1114
+ question: row.question,
1115
+ categories: row.categories,
1116
+ yesPrice: row.yesPrice,
1117
+ noPrice: row.noPrice,
1118
+ yesPriceLabel: row.yesPriceLabel,
1119
+ noPriceLabel: row.noPriceLabel,
1120
+ volume: trueoCompactVolumeLabel(row.size),
1121
+ tvl: row.tvl,
1122
+ expiresAt: row.expiresAt,
1123
+ expiresAtLabel: row.expiresAtLabel,
1124
+ tradingEndsLabel: trueoTradingEndsCopy(row),
1125
+ endOfTrading: row.endOfTrading,
1126
+ status,
1127
+ outcome: row.outcome,
1128
+ statusUpdatedAt: row.statusUpdatedAt,
1129
+ resolutionLabel: trueoResolutionCopy(row),
1130
+ chainId: row.chainId,
1131
+ paymentSymbol: row.paymentTokenSymbol,
1132
+ tradable: trueoMarketVotingOpen(row),
1133
+ rules: row.rules,
1134
+ source: row.source,
1135
+ imageUrl: row.imageUrl
1136
+ };
1137
+ }
1138
+ async function searchPredictionMarkets(args) {
1139
+ const venues = (args.venues ?? ["trueo"]).map((v) => v.trim().toLowerCase()).filter(Boolean);
1140
+ if (venues.length && !venues.includes("trueo")) {
1141
+ return {
1142
+ markets: [],
1143
+ notes: "No supported venues in the filter. v1 adapter is trueo (Base).",
1144
+ hasMore: false,
1145
+ includeAll: false,
1146
+ nextOffset: 0,
1147
+ nextIndexBase: 0
1148
+ };
1149
+ }
1150
+ const includeAll = args.includeAll === true;
1151
+ const offset = Math.max(args.offset ?? 0, 0);
1152
+ const indexBase = Math.max(args.indexBase ?? 0, 0);
1153
+ const page = await listTrueoMarketsPage({
1154
+ query: args.query,
1155
+ category: args.category,
1156
+ offset,
1157
+ includeAll,
1158
+ trending: args.trending,
1159
+ excludeAddresses: args.excludeAddresses
1160
+ });
1161
+ const markets = page.markets.map(trueoMarketToPredictionRow).slice(0, args.limit ?? TRUEO_MARKET_PAGE_SIZE).map((row, i) => ({ ...row, index: indexBase + i + 1 }));
1162
+ const nextIndexBase = indexBase + markets.length;
1163
+ const scope = trueoSearchScopeNote(includeAll);
1164
+ const q = args.query?.trim() ?? "";
1165
+ if (q && markets.length === 0) {
1166
+ return {
1167
+ markets,
1168
+ hasMore: page.hasMore,
1169
+ nextOffset: page.nextOffset,
1170
+ nextIndexBase,
1171
+ includeAll,
1172
+ notes: `No live or recent title match for ${JSON.stringify(q)} after scanning the catalog. Do not list trending unless the operator asked. ${scope}`
1173
+ };
1174
+ }
1175
+ const more = page.hasMore ? `More: search_prediction_markets with offset=${page.nextOffset}, trending=false, indexBase=${nextIndexBase}, excludeAddresses from this page's venueMarketIds.` : "End of results.";
1176
+ return {
1177
+ markets,
1178
+ hasMore: page.hasMore,
1179
+ nextOffset: page.nextOffset,
1180
+ nextIndexBase,
1181
+ includeAll,
1182
+ notes: `${scope} ${more} Pick #N then get_prediction_market.`
1183
+ };
1184
+ }
1185
+ function buildPredictionMarketEnvelope(market) {
1186
+ return { kind: PREDICTION_MARKET_V1_KIND, market };
1187
+ }
1188
+ async function searchPredictionMarketsSummary(input) {
1189
+ return searchPredictionMarkets(input);
1190
+ }
1191
+ function trueoHoldingTokenAddressesFromRegistry(tokens) {
1192
+ const out = [];
1193
+ const seen = /* @__PURE__ */ new Set();
1194
+ for (const t of tokens) {
1195
+ const addr = String(t.contractAddress ?? "").trim().toLowerCase();
1196
+ if (!addr || seen.has(addr)) continue;
1197
+ if (!isTrueoOutcomeTokenLabel(t.symbol, t.name)) continue;
1198
+ seen.add(addr);
1199
+ out.push(addr);
1200
+ }
1201
+ return out;
1202
+ }
1203
+ async function listPredictionMarketsForHoldings(args) {
1204
+ const marketIds = new Set(
1205
+ (args.marketAddresses ?? []).map((a) => a.trim().toLowerCase()).filter((a) => a.startsWith("0x"))
1206
+ );
1207
+ const tokens = (args.tokenAddresses ?? []).map((a) => a.trim().toLowerCase()).filter((a) => a.startsWith("0x"));
1208
+ for (const token of tokens) {
1209
+ try {
1210
+ const page = await searchTrueoMarketsPage({
1211
+ query: token,
1212
+ includeAll: true,
1213
+ limit: TRUEO_MARKET_PAGE_SIZE
1214
+ });
1215
+ for (const row of page.markets) {
1216
+ if (row.yesTokenAddress === token || row.noTokenAddress === token || row.address === token) {
1217
+ marketIds.add(row.address);
1218
+ }
1219
+ }
1220
+ } catch {
1221
+ }
1222
+ }
1223
+ const markets = [];
1224
+ let i = 0;
1225
+ for (const id of marketIds) {
1226
+ try {
1227
+ const row = await fetchTrueoMarket({ marketAddress: id });
1228
+ markets.push({ ...trueoMarketToPredictionRow(row), index: ++i });
1229
+ } catch {
1230
+ }
1231
+ }
1232
+ const notes = markets.length === 0 ? "No matching holdings. Pass YES/NO token addresses from get_token_registry (or add_to_token_registry after a bet) and/or marketAddresses from prior bets." : `Live status for ${markets.length} market(s) you hold or named. Pick #N then get_prediction_market.`;
1233
+ return {
1234
+ markets,
1235
+ notes,
1236
+ hasMore: false,
1237
+ nextOffset: 0,
1238
+ nextIndexBase: markets.length,
1239
+ includeAll: true
1240
+ };
1241
+ }
1242
+ async function listMyPredictionMarketsSummary(input) {
1243
+ return listPredictionMarketsForHoldings(input);
1244
+ }
1245
+ async function getPredictionMarketSummary(input) {
1246
+ const venue = (input.venue ?? "trueo").trim().toLowerCase();
1247
+ if (venue !== "trueo") {
1248
+ throw new Error(`Venue "${venue}" is not supported. v1 adapter is trueo.`);
1249
+ }
1250
+ const row = await fetchTrueoMarket({ marketAddress: input.venueMarketId });
1251
+ let ohlc = [];
1252
+ let orderbook = null;
1253
+ try {
1254
+ ohlc = await fetchTrueoChanceSeries({
1255
+ poolId: row.yesPoolAddress
1256
+ });
1257
+ } catch {
1258
+ ohlc = [];
1259
+ }
1260
+ try {
1261
+ orderbook = await fetchTrueoOrderbook({ marketAddress: row.address, side: "yes" });
1262
+ } catch {
1263
+ orderbook = null;
1264
+ }
1265
+ const market = {
1266
+ ...trueoMarketToPredictionRow(row),
1267
+ rules: row.rules,
1268
+ source: row.source,
1269
+ yesTokenAddress: row.yesTokenAddress,
1270
+ noTokenAddress: row.noTokenAddress,
1271
+ yesPoolAddress: row.yesPoolAddress,
1272
+ noPoolAddress: row.noPoolAddress,
1273
+ paymentTokenAddress: row.paymentTokenAddress,
1274
+ endOfTrading: row.endOfTrading,
1275
+ ohlc,
1276
+ orderbook
1277
+ };
1278
+ return {
1279
+ kind: PREDICTION_MARKET_V1_KIND,
1280
+ ...market,
1281
+ envelope: buildPredictionMarketEnvelope(market)
1282
+ };
1283
+ }
1284
+
1285
+ // src/protocols/evm/trueo/purpose.ts
1286
+ function buildTrueoPurposePrefill(args) {
1287
+ const chainId = args.chainId ?? TRUEO_BASE_CHAIN_ID;
1288
+ const q = args.question?.trim() ? ` on ${args.question.trim()}` : "";
1289
+ const amt = args.amountHuman?.trim() ?? "";
1290
+ const sym = args.paymentSymbol?.trim() || "TYD";
1291
+ const side = args.side === "no" ? "No" : "Yes";
1292
+ switch (args.action) {
1293
+ case "wrapTyd":
1294
+ return `Trueo: mint ${amt || ""} TYD from USDC on Base (chainId ${chainId})`.replace(/\s+/g, " ").trim();
1295
+ case "unwrapTyd":
1296
+ return `Trueo: unwrap ${amt || ""} TYD to USDC on Base (chainId ${chainId})`.replace(/\s+/g, " ").trim();
1297
+ case "mint":
1298
+ return `Trueo: mint ${amt || "YES+NO"} ${sym}${q} on Base (chainId ${chainId})`;
1299
+ case "burn":
1300
+ return `Trueo: burn ${amt || "YES+NO"}${q} on Base (chainId ${chainId})`;
1301
+ case "redeem":
1302
+ return `Trueo: redeem ${amt || "winning tokens"}${q} on Base (chainId ${chainId})`;
1303
+ case "swap":
1304
+ return `Trueo: buy ${side} ${amt || ""} ${sym}${q} on Base (chainId ${chainId})`.replace(/\s+/g, " ").trim();
1305
+ case "createOrder":
1306
+ return `Trueo: limit ${side} ${amt || ""} ${sym}${q} on Base (chainId ${chainId})`.replace(/\s+/g, " ").trim();
1307
+ case "cancelOrder":
1308
+ return `Trueo: cancel order${q} on Base (chainId ${chainId})`;
1309
+ default:
1310
+ return `Trueo${q} on Base (chainId ${chainId})`;
1311
+ }
1312
+ }
1313
+
1314
+ // src/core/expiry.ts
1315
+ var DEFAULT_DEFI_MULTISIGN_EXPIRY_SECONDS = 30 * 60;
1316
+ var DEFI_PROTOCOLS_WITH_30MIN_EXPIRY = /* @__PURE__ */ new Set([
1317
+ "uniswap-v4",
1318
+ "gmx",
1319
+ "hyperliquid",
1320
+ "arcus",
1321
+ "curve-dao",
1322
+ "aerodrome",
1323
+ "pendle",
1324
+ "derive",
1325
+ "trueo"
1326
+ ]);
1327
+ function defiMultisignExpiryUnixSeconds(protocolId, explicitExpiryDate) {
1328
+ if (typeof explicitExpiryDate === "number" && Number.isFinite(explicitExpiryDate) && explicitExpiryDate > 0) {
1329
+ return Math.floor(explicitExpiryDate);
1330
+ }
1331
+ if (DEFI_PROTOCOLS_WITH_30MIN_EXPIRY.has(protocolId)) {
1332
+ return Math.floor(Date.now() / 1e3) + DEFAULT_DEFI_MULTISIGN_EXPIRY_SECONDS;
1333
+ }
1334
+ return void 0;
1335
+ }
1336
+
1337
+ // src/core/purpose.ts
1338
+ function mergePurposeText(purposeText, purposeSuffix) {
1339
+ const t = (purposeText ?? "").trim();
1340
+ const suffix = (purposeSuffix ?? "").trim();
1341
+ if (!suffix) return t;
1342
+ return t ? `${t}
1343
+
1344
+ ${suffix}` : suffix;
1345
+ }
1346
+
1347
+ // src/core/envelope.ts
1348
+ function finalizeMultisign(input) {
1349
+ const { keyGen, destinationChainID, legs } = input;
1350
+ if (legs.length === 0) {
1351
+ throw new Error("finalizeMultisign requires at least one leg");
1352
+ }
1353
+ const ph = (keyGen.pubkeyhex ?? "").trim();
1354
+ if (!ph) throw new Error("keyGen pubKey (pubkeyhex) is required");
1355
+ const keyList = keyGen.keylist ?? [];
1356
+ const clientId = continuumNodeSdk.getClientIdFromKeyGenResult(keyGen);
1357
+ const first = legs[0];
1358
+ const messageHashes = legs.map((l) => l.msgHash);
1359
+ const messageRawBatch = legs.map((l) => l.msgRaw);
1360
+ const batchMeta = legs.map((l) => ({
1361
+ destinationAddress: l.destinationAddress,
1362
+ signatureText: l.signatureText,
1363
+ ...l.audit
1364
+ }));
1365
+ const proposalTxParams = legs.map((l) => l.proposalTxParams).filter((p) => p != null && typeof p === "object");
1366
+ const extraPayload = {
1367
+ batchMeta,
1368
+ ...input.extraJSON ?? {}
1369
+ };
1370
+ const extraJSON = JSON.stringify(extraPayload, (_, v) => typeof v === "bigint" ? v.toString() : v);
1371
+ const bodyForSign = {
1372
+ keyList,
1373
+ pubKey: ph,
1374
+ msgHash: messageHashes[0],
1375
+ msgRaw: first.msgRaw,
1376
+ destinationChainID,
1377
+ destinationAddress: input.destinationAddress ?? first.destinationAddress,
1378
+ extraJSON,
1379
+ signatureText: first.signatureText,
1380
+ purpose: mergePurposeText(input.purposeText, input.purposeSuffix),
1381
+ ...first.feeSnapshot
1382
+ };
1383
+ if (legs.length > 1) {
1384
+ bodyForSign.messageHashes = messageHashes;
1385
+ bodyForSign.messageRawBatch = messageRawBatch;
1386
+ }
1387
+ if (proposalTxParams.length > 0) {
1388
+ bodyForSign.proposalTxParams = proposalTxParams;
1389
+ }
1390
+ const valueWei = first.valueWei;
1391
+ if (valueWei != null && valueWei > 0n) {
1392
+ bodyForSign.value = valueWei.toString();
1393
+ }
1394
+ if (clientId) bodyForSign.clientId = clientId;
1395
+ if (input.expiryDate != null && input.expiryDate > 0) {
1396
+ bodyForSign.expiryDate = Math.floor(input.expiryDate);
1397
+ }
1398
+ return { bodyForSign, messageToSign: JSON.stringify(bodyForSign) };
1399
+ }
1400
+ function routerSwapGasLimitFromEstimate(estimatedGas, chainGasLimit) {
1401
+ if (chainGasLimit != null && Number.isFinite(chainGasLimit) && chainGasLimit > 0) {
1402
+ return continuumNodeSdk.gasLimitFromEstimateAndChainConfig(estimatedGas, chainGasLimit);
1403
+ }
1404
+ return (estimatedGas * 12n + 9n) / 10n;
1405
+ }
1406
+
1407
+ // src/chains/evm/buildBatch.ts
1408
+ async function buildEvmMultisignBatch(args) {
1409
+ const { context, steps } = args;
1410
+ const {
1411
+ chainId,
1412
+ rpcUrl,
1413
+ executorAddress,
1414
+ chainDetail,
1415
+ useCustomGas,
1416
+ customGasChainDetails,
1417
+ keyGen,
1418
+ purposeText
1419
+ } = context;
1420
+ if (steps.length === 0) throw new Error("buildEvmMultisignBatch requires at least one step");
1421
+ const ch = viem.defineChain({
1422
+ id: chainId,
1423
+ name: "Destination",
1424
+ nativeCurrency: { decimals: 18, name: "Ether", symbol: "ETH" },
1425
+ rpcUrls: { default: { http: [rpcUrl] } }
1426
+ });
1427
+ const publicClient2 = viem.createPublicClient({ chain: ch, transport: defiEvmTransport(rpcUrl) });
1428
+ const feeParams = await continuumNodeSdk.fetchChainFeeParams(rpcUrl, chainId);
1429
+ const legacy = Boolean(chainDetail?.legacy) || !feeParams.isEip1559;
1430
+ const latestBaseFeeWei = !legacy ? (await publicClient2.getBlock({ blockTag: "latest" })).baseFeePerGas ?? 0n : 0n;
1431
+ const gasLimitConfig = useCustomGas && chainDetail?.gasLimit != null ? Number(chainDetail.gasLimit) : void 0;
1432
+ const chainGasLimitRouter = chainDetail?.gasLimit != null && Number.isFinite(Number(chainDetail.gasLimit)) && Number(chainDetail.gasLimit) > 0 ? Number(chainDetail.gasLimit) : void 0;
1433
+ const gasFeeMultiplier = useCustomGas && chainDetail?.gasMultiplier != null ? Number(chainDetail.gasMultiplier) : void 0;
1434
+ const executor = viem.getAddress(executorAddress);
1435
+ const baseNonce = await publicClient2.getTransactionCount({ address: executor, blockTag: "pending" });
1436
+ const legs = [];
1437
+ for (let i = 0; i < steps.length; i++) {
1438
+ const step = steps[i];
1439
+ const currentNonce = baseNonce + i;
1440
+ let estimatedGas;
1441
+ if (args.estimateGasForStep) {
1442
+ estimatedGas = await args.estimateGasForStep({ step, index: i, publicClient: publicClient2, executor });
1443
+ } else {
1444
+ try {
1445
+ estimatedGas = await publicClient2.estimateGas({
1446
+ to: step.to,
1447
+ data: step.data,
1448
+ value: step.value,
1449
+ account: executor
1450
+ });
1451
+ } catch {
1452
+ estimatedGas = step.fallbackGas ?? 100000n;
1453
+ }
1454
+ }
1455
+ let gasLimitI;
1456
+ if (args.resolveGasLimit) {
1457
+ gasLimitI = await args.resolveGasLimit({ step, index: i, estimatedGas, publicClient: publicClient2 });
1458
+ } else if (step.routerSwap) {
1459
+ gasLimitI = routerSwapGasLimitFromEstimate(estimatedGas, chainGasLimitRouter);
1460
+ } else {
1461
+ gasLimitI = useCustomGas ? continuumNodeSdk.gasLimitFromEstimateAndChainConfig(estimatedGas, gasLimitConfig) : estimatedGas;
1462
+ }
1463
+ let proposalTxParams;
1464
+ let feeSnapshot;
1465
+ let serialized;
1466
+ if (legacy) {
1467
+ let gasPriceWei = await publicClient2.getGasPrice();
1468
+ if (useCustomGas && gasFeeMultiplier != null && gasFeeMultiplier > 0) {
1469
+ gasPriceWei = gasPriceWei * BigInt(100 + gasFeeMultiplier) / 100n;
1470
+ }
1471
+ if (useCustomGas && chainDetail?.gasPrice != null && chainDetail.gasPrice > 0) {
1472
+ const configured = viem.parseGwei(continuumNodeSdk.gweiToDecimalString(Number(chainDetail.gasPrice)));
1473
+ if (configured > gasPriceWei) gasPriceWei = configured;
1474
+ }
1475
+ serialized = viem.serializeTransaction({
1476
+ type: "legacy",
1477
+ to: step.to,
1478
+ data: step.data,
1479
+ value: step.value,
1480
+ gas: gasLimitI,
1481
+ gasPrice: gasPriceWei,
1482
+ nonce: currentNonce,
1483
+ chainId
1484
+ });
1485
+ proposalTxParams = {
1486
+ nonce: currentNonce,
1487
+ gasLimit: gasLimitI.toString(),
1488
+ txType: "legacy",
1489
+ gasPrice: gasPriceWei.toString()
1490
+ };
1491
+ feeSnapshot = continuumNodeSdk.proposalTxParamsToFeeSnapshot(proposalTxParams);
1492
+ } else {
1493
+ const fetchedBase = feeParams.baseFeeGwei ?? 0;
1494
+ const fetchedPriority = feeParams.priorityFeeGwei ?? 0;
1495
+ const configuredBase = useCustomGas && chainDetail?.baseFee != null ? Number(chainDetail.baseFee) : 0;
1496
+ const configuredPriority = useCustomGas && chainDetail?.priorityFee != null ? Number(chainDetail.priorityFee) : 0;
1497
+ const effectiveBaseFeeGwei = Math.max(fetchedBase, configuredBase);
1498
+ const effectivePriorityFeeGwei = Math.max(fetchedPriority, configuredPriority);
1499
+ const baseFeeMultiplierPct = useCustomGas && chainDetail?.baseFeeMultiplier != null ? Math.max(100, Number(chainDetail.baseFeeMultiplier)) : 100;
1500
+ const baseComponentGwei = effectiveBaseFeeGwei * baseFeeMultiplierPct / 100;
1501
+ const maxFeePerGasGwei = baseComponentGwei + effectivePriorityFeeGwei;
1502
+ let maxPriorityFeePerGas = effectivePriorityFeeGwei > 0 ? viem.parseGwei(continuumNodeSdk.gweiToDecimalString(effectivePriorityFeeGwei)) : viem.parseGwei("1");
1503
+ let maxFeePerGas = viem.parseGwei(continuumNodeSdk.gweiToDecimalString(maxFeePerGasGwei));
1504
+ if (useCustomGas && gasFeeMultiplier != null && gasFeeMultiplier > 0) {
1505
+ maxPriorityFeePerGas = maxPriorityFeePerGas * BigInt(100 + gasFeeMultiplier) / 100n;
1506
+ maxFeePerGas = maxFeePerGas * BigInt(100 + gasFeeMultiplier) / 100n;
1507
+ }
1508
+ ({ maxFeePerGas, maxPriorityFeePerGas } = continuumNodeSdk.alignEip1559FeesWithLatestBase(
1509
+ maxFeePerGas,
1510
+ maxPriorityFeePerGas,
1511
+ latestBaseFeeWei
1512
+ ));
1513
+ serialized = viem.serializeTransaction({
1514
+ type: "eip1559",
1515
+ to: step.to,
1516
+ data: step.data,
1517
+ value: step.value,
1518
+ gas: gasLimitI,
1519
+ maxFeePerGas,
1520
+ maxPriorityFeePerGas,
1521
+ nonce: currentNonce,
1522
+ chainId
1523
+ });
1524
+ proposalTxParams = {
1525
+ nonce: currentNonce,
1526
+ gasLimit: gasLimitI.toString(),
1527
+ txType: "eip1559",
1528
+ maxFeePerGas: maxFeePerGas.toString(),
1529
+ maxPriorityFeePerGas: maxPriorityFeePerGas.toString()
1530
+ };
1531
+ feeSnapshot = i === 0 ? continuumNodeSdk.proposalTxParamsToFeeSnapshot(proposalTxParams) : {};
1532
+ }
1533
+ const h = viem.keccak256(serialized);
1534
+ const msgHash = h.startsWith("0x") ? h.slice(2) : h;
1535
+ const batchMetaExtra = args.buildBatchMeta({ step, index: i, gasLimit: gasLimitI });
1536
+ legs.push({
1537
+ msgHash,
1538
+ msgRaw: i === 0 && args.firstMsgRawNo0x != null ? args.firstMsgRawNo0x : serialized,
1539
+ destinationAddress: step.to,
1540
+ signatureText: typeof batchMetaExtra.signatureText === "string" ? batchMetaExtra.signatureText : JSON.stringify(batchMetaExtra.signatureText ?? {}),
1541
+ audit: batchMetaExtra,
1542
+ feeSnapshot: i === 0 ? feeSnapshot : {},
1543
+ proposalTxParams,
1544
+ valueWei: i === 0 ? step.value : void 0
1545
+ });
1546
+ if (i === 0 && args.firstMsgRawNo0x != null) {
1547
+ legs[0].msgRaw = args.firstMsgRawNo0x;
1548
+ }
1549
+ }
1550
+ const extraJSON = {};
1551
+ if (useCustomGas && customGasChainDetails && Object.keys(customGasChainDetails).length > 0) {
1552
+ extraJSON.customGasChainDetails = customGasChainDetails;
1553
+ }
1554
+ const result = finalizeMultisign({
1555
+ keyGen,
1556
+ purposeText,
1557
+ purposeSuffix: args.purposeSuffix,
1558
+ destinationChainID: String(chainId),
1559
+ destinationAddress: args.destinationAddress ?? steps[0].to,
1560
+ legs,
1561
+ extraJSON: Object.keys(extraJSON).length > 0 ? extraJSON : void 0,
1562
+ expiryDate: context.expiryDate
1563
+ });
1564
+ const pv = args.payableValueWei;
1565
+ if (pv != null && pv > 0n) {
1566
+ result.bodyForSign.value = pv.toString();
1567
+ }
1568
+ return result;
1569
+ }
1570
+
1571
+ // src/protocols/evm/trueo/multisign.ts
1572
+ var TRUEO_APPROVE_FALLBACK_GAS = 80000n;
1573
+ var TRUEO_MINT_FALLBACK_GAS = 450000n;
1574
+ var TRUEO_TYD_VAULT_FALLBACK_GAS = 350000n;
1575
+ var TRUEO_SWAP_FALLBACK_GAS = 650000n;
1576
+ var TRUEO_ORDER_FALLBACK_GAS = 520000n;
1577
+ function client(rpcUrl) {
1578
+ const chain = viem.defineChain({
1579
+ id: TRUEO_BASE_CHAIN_ID,
1580
+ name: "Base",
1581
+ nativeCurrency: { decimals: 18, name: "Ether", symbol: "ETH" },
1582
+ rpcUrls: { default: { http: [rpcUrl] } }
1583
+ });
1584
+ return viem.createPublicClient({ chain, transport: defiEvmTransport(rpcUrl) });
1585
+ }
1586
+ async function allowance(args) {
1587
+ return client(args.rpcUrl).readContract({
1588
+ address: args.token,
1589
+ abi: trueoErc20Abi,
1590
+ functionName: "allowance",
1591
+ args: [args.owner, args.spender]
1592
+ });
1593
+ }
1594
+ async function pushApproveIfNeeded(args) {
1595
+ const current = await allowance({
1596
+ rpcUrl: args.rpcUrl,
1597
+ token: args.token,
1598
+ owner: args.owner,
1599
+ spender: args.spender
1600
+ });
1601
+ if (current >= args.amount) return;
1602
+ if (current > 0n) {
1603
+ args.steps.push({
1604
+ kind: "approve_zero",
1605
+ to: args.token,
1606
+ data: encodeErc20Approve(args.spender, 0n),
1607
+ value: 0n,
1608
+ fallbackGas: TRUEO_APPROVE_FALLBACK_GAS
1609
+ });
1610
+ }
1611
+ args.steps.push({
1612
+ kind: "approve",
1613
+ to: args.token,
1614
+ data: encodeErc20Approve(args.spender, args.amount),
1615
+ value: 0n,
1616
+ fallbackGas: TRUEO_APPROVE_FALLBACK_GAS
1617
+ });
1618
+ }
1619
+ function mergeExtraJson(result, extra) {
1620
+ const body = result.bodyForSign;
1621
+ const existing = typeof body.extraJSON === "string" ? JSON.parse(body.extraJSON) : body.extraJSON ?? {};
1622
+ body.extraJSON = JSON.stringify({ ...existing, ...extra });
1623
+ }
1624
+ async function finalizeTrueo(args) {
1625
+ const expiryDate = defiMultisignExpiryUnixSeconds(TRUEO_PROTOCOL_ID, args.expiryDate);
1626
+ const first = args.steps[0];
1627
+ if (!first) throw new Error("Trueo: no transaction steps.");
1628
+ const firstDataNo0x = first.data.startsWith("0x") ? first.data.slice(2) : first.data;
1629
+ const result = await buildEvmMultisignBatch({
1630
+ context: {
1631
+ chainCategory: "evm",
1632
+ keyGen: args.keyGen,
1633
+ purposeText: args.purposeText,
1634
+ chainId: TRUEO_BASE_CHAIN_ID,
1635
+ rpcUrl: args.rpcUrl,
1636
+ executorAddress: args.executorAddress,
1637
+ chainDetail: args.chainDetail,
1638
+ useCustomGas: args.useCustomGas,
1639
+ customGasChainDetails: args.customGasChainDetails,
1640
+ expiryDate
1641
+ },
1642
+ steps: args.steps,
1643
+ purposeSuffix: args.purposeSuffix,
1644
+ firstMsgRawNo0x: firstDataNo0x,
1645
+ destinationAddress: first.to,
1646
+ buildBatchMeta: ({ step, index }) => {
1647
+ const s = step;
1648
+ return {
1649
+ signatureText: JSON.stringify({
1650
+ kind: "Trueo",
1651
+ name: s.kind,
1652
+ index,
1653
+ chainId: TRUEO_BASE_CHAIN_ID
1654
+ }),
1655
+ evm: { type: `trueo_${s.kind}`, version: 1, chainId: String(TRUEO_BASE_CHAIN_ID) }
1656
+ };
1657
+ }
1658
+ });
1659
+ if (args.betExtra) mergeExtraJson(result, args.betExtra);
1660
+ return result;
1661
+ }
1662
+ function parseAmount(human, decimals) {
1663
+ const amt = viem.parseUnits(String(human).trim(), decimals);
1664
+ if (amt <= 0n) throw new Error("Amount must be greater than zero.");
1665
+ return amt;
1666
+ }
1667
+ async function assertTrueoTydVaultUnderlying(rpcUrl) {
1668
+ const underlying = await client(rpcUrl).readContract({
1669
+ address: TRUEO_TYD,
1670
+ abi: trueoTydVaultAbi,
1671
+ functionName: "asset"
1672
+ });
1673
+ if (viem.getAddress(underlying) !== TRUEO_USDC) {
1674
+ throw new Error("TYD vault underlying is not Base USDC.");
1675
+ }
1676
+ }
1677
+ async function buildEvmMultisignBodyTrueoWrapTyd(args) {
1678
+ assertTrueoChainId(args.chainId);
1679
+ const executor = viem.getAddress(args.executorAddress);
1680
+ const amount = parseAmount(args.amountHuman, 6);
1681
+ await assertTrueoTydVaultUnderlying(args.rpcUrl);
1682
+ const steps = [];
1683
+ await pushApproveIfNeeded({
1684
+ steps,
1685
+ rpcUrl: args.rpcUrl,
1686
+ token: TRUEO_USDC,
1687
+ owner: executor,
1688
+ spender: TRUEO_TYD,
1689
+ amount
1690
+ });
1691
+ steps.push({
1692
+ kind: "wrap_tyd",
1693
+ to: TRUEO_TYD,
1694
+ data: encodeTrueoTydDeposit(amount, executor),
1695
+ value: 0n,
1696
+ fallbackGas: TRUEO_TYD_VAULT_FALLBACK_GAS
1697
+ });
1698
+ const purposeText = args.purposeText.trim() || buildTrueoPurposePrefill({ action: "wrapTyd", amountHuman: args.amountHuman, paymentSymbol: "USDC" });
1699
+ return finalizeTrueo({
1700
+ ...args,
1701
+ executorAddress: executor,
1702
+ purposeText,
1703
+ purposeSuffix: "Trueo: mint TYD from USDC (Yearn ERC-4626 deposit).",
1704
+ steps
1705
+ });
1706
+ }
1707
+ async function buildEvmMultisignBodyTrueoUnwrapTyd(args) {
1708
+ assertTrueoChainId(args.chainId);
1709
+ const executor = viem.getAddress(args.executorAddress);
1710
+ const amount = parseAmount(args.amountHuman, TRUEO_TYD_DECIMALS);
1711
+ await assertTrueoTydVaultUnderlying(args.rpcUrl);
1712
+ const steps = [
1713
+ {
1714
+ kind: "unwrap_tyd",
1715
+ to: TRUEO_TYD,
1716
+ data: encodeTrueoTydRedeem(amount, executor, executor),
1717
+ value: 0n,
1718
+ fallbackGas: TRUEO_TYD_VAULT_FALLBACK_GAS
1719
+ }
1720
+ ];
1721
+ const purposeText = args.purposeText.trim() || buildTrueoPurposePrefill({ action: "unwrapTyd", amountHuman: args.amountHuman, paymentSymbol: "TYD" });
1722
+ return finalizeTrueo({
1723
+ ...args,
1724
+ executorAddress: executor,
1725
+ purposeText,
1726
+ purposeSuffix: "Trueo: unwrap TYD to USDC (Yearn ERC-4626 redeem).",
1727
+ steps
1728
+ });
1729
+ }
1730
+ async function buildEvmMultisignBodyTrueoMint(args) {
1731
+ assertTrueoChainId(args.chainId);
1732
+ const executor = viem.getAddress(args.executorAddress);
1733
+ const market = viem.getAddress(args.marketAddress);
1734
+ const paymentKind = args.paymentKind === "usdc" ? "usdc" : "tyd";
1735
+ const decimals = paymentKind === "usdc" ? 6 : TRUEO_TYD_DECIMALS;
1736
+ const amount = parseAmount(args.amountHuman, decimals);
1737
+ const row = await fetchTrueoMarket({ marketAddress: market });
1738
+ const steps = [];
1739
+ if (paymentKind === "usdc") {
1740
+ await pushApproveIfNeeded({
1741
+ steps,
1742
+ rpcUrl: args.rpcUrl,
1743
+ token: TRUEO_USDC,
1744
+ owner: executor,
1745
+ spender: TRUEO_TRUTH_MARKET_ADAPTER,
1746
+ amount
1747
+ });
1748
+ steps.push({
1749
+ kind: "adapter_mint",
1750
+ to: TRUEO_TRUTH_MARKET_ADAPTER,
1751
+ data: encodeTrueoAdapterMint(market, amount),
1752
+ value: 0n,
1753
+ fallbackGas: TRUEO_MINT_FALLBACK_GAS
1754
+ });
1755
+ } else {
1756
+ await pushApproveIfNeeded({
1757
+ steps,
1758
+ rpcUrl: args.rpcUrl,
1759
+ token: TRUEO_TYD,
1760
+ owner: executor,
1761
+ spender: market,
1762
+ amount
1763
+ });
1764
+ steps.push({
1765
+ kind: "mint",
1766
+ to: market,
1767
+ data: encodeTrueoMint(amount),
1768
+ value: 0n,
1769
+ fallbackGas: TRUEO_MINT_FALLBACK_GAS
1770
+ });
1771
+ }
1772
+ const purposeText = args.purposeText.trim() || buildTrueoPurposePrefill({
1773
+ action: "mint",
1774
+ amountHuman: args.amountHuman,
1775
+ paymentSymbol: paymentKind === "usdc" ? "USDC" : "TYD",
1776
+ question: row.question
1777
+ });
1778
+ return finalizeTrueo({
1779
+ ...args,
1780
+ executorAddress: executor,
1781
+ purposeText,
1782
+ purposeSuffix: `Trueo: mint YES+NO on ${row.question || market}.`,
1783
+ steps
1784
+ });
1785
+ }
1786
+ async function buildEvmMultisignBodyTrueoBurn(args) {
1787
+ assertTrueoChainId(args.chainId);
1788
+ const executor = viem.getAddress(args.executorAddress);
1789
+ const market = viem.getAddress(args.marketAddress);
1790
+ const row = await fetchTrueoMarket({ marketAddress: market });
1791
+ const amount = parseAmount(args.amountHuman, 18);
1792
+ const steps = [];
1793
+ const paymentKind = args.paymentKind === "usdc" ? "usdc" : "tyd";
1794
+ if (paymentKind === "usdc") {
1795
+ await pushApproveIfNeeded({
1796
+ steps,
1797
+ rpcUrl: args.rpcUrl,
1798
+ token: viem.getAddress(row.yesTokenAddress),
1799
+ owner: executor,
1800
+ spender: TRUEO_TRUTH_MARKET_ADAPTER,
1801
+ amount
1802
+ });
1803
+ await pushApproveIfNeeded({
1804
+ steps,
1805
+ rpcUrl: args.rpcUrl,
1806
+ token: viem.getAddress(row.noTokenAddress),
1807
+ owner: executor,
1808
+ spender: TRUEO_TRUTH_MARKET_ADAPTER,
1809
+ amount
1810
+ });
1811
+ steps.push({
1812
+ kind: "adapter_burn",
1813
+ to: TRUEO_TRUTH_MARKET_ADAPTER,
1814
+ data: encodeTrueoAdapterBurn(market, amount),
1815
+ value: 0n,
1816
+ fallbackGas: TRUEO_MINT_FALLBACK_GAS
1817
+ });
1818
+ } else {
1819
+ await pushApproveIfNeeded({
1820
+ steps,
1821
+ rpcUrl: args.rpcUrl,
1822
+ token: viem.getAddress(row.yesTokenAddress),
1823
+ owner: executor,
1824
+ spender: market,
1825
+ amount
1826
+ });
1827
+ await pushApproveIfNeeded({
1828
+ steps,
1829
+ rpcUrl: args.rpcUrl,
1830
+ token: viem.getAddress(row.noTokenAddress),
1831
+ owner: executor,
1832
+ spender: market,
1833
+ amount
1834
+ });
1835
+ steps.push({
1836
+ kind: "burn",
1837
+ to: market,
1838
+ data: encodeTrueoBurn(amount),
1839
+ value: 0n,
1840
+ fallbackGas: TRUEO_MINT_FALLBACK_GAS
1841
+ });
1842
+ }
1843
+ const purposeText = args.purposeText.trim() || buildTrueoPurposePrefill({ action: "burn", amountHuman: args.amountHuman, question: row.question });
1844
+ return finalizeTrueo({
1845
+ ...args,
1846
+ executorAddress: executor,
1847
+ purposeText,
1848
+ purposeSuffix: `Trueo: burn YES+NO on ${row.question || market}.`,
1849
+ steps
1850
+ });
1851
+ }
1852
+ async function buildEvmMultisignBodyTrueoRedeem(args) {
1853
+ assertTrueoChainId(args.chainId);
1854
+ const executor = viem.getAddress(args.executorAddress);
1855
+ const market = viem.getAddress(args.marketAddress);
1856
+ const row = await fetchTrueoMarket({ marketAddress: market });
1857
+ const amount = parseAmount(args.amountHuman, 18);
1858
+ const steps = [];
1859
+ const paymentKind = args.paymentKind === "usdc" ? "usdc" : "tyd";
1860
+ const winning = row.yesTokenAddress;
1861
+ if (paymentKind === "usdc") {
1862
+ await pushApproveIfNeeded({
1863
+ steps,
1864
+ rpcUrl: args.rpcUrl,
1865
+ token: viem.getAddress(winning),
1866
+ owner: executor,
1867
+ spender: TRUEO_TRUTH_MARKET_ADAPTER,
1868
+ amount
1869
+ });
1870
+ await pushApproveIfNeeded({
1871
+ steps,
1872
+ rpcUrl: args.rpcUrl,
1873
+ token: viem.getAddress(row.noTokenAddress),
1874
+ owner: executor,
1875
+ spender: TRUEO_TRUTH_MARKET_ADAPTER,
1876
+ amount
1877
+ });
1878
+ steps.push({
1879
+ kind: "adapter_redeem",
1880
+ to: TRUEO_TRUTH_MARKET_ADAPTER,
1881
+ data: encodeTrueoAdapterRedeem(market, amount),
1882
+ value: 0n,
1883
+ fallbackGas: TRUEO_MINT_FALLBACK_GAS
1884
+ });
1885
+ } else {
1886
+ await pushApproveIfNeeded({
1887
+ steps,
1888
+ rpcUrl: args.rpcUrl,
1889
+ token: viem.getAddress(winning),
1890
+ owner: executor,
1891
+ spender: market,
1892
+ amount
1893
+ });
1894
+ await pushApproveIfNeeded({
1895
+ steps,
1896
+ rpcUrl: args.rpcUrl,
1897
+ token: viem.getAddress(row.noTokenAddress),
1898
+ owner: executor,
1899
+ spender: market,
1900
+ amount
1901
+ });
1902
+ steps.push({
1903
+ kind: "redeem",
1904
+ to: market,
1905
+ data: encodeTrueoRedeem(amount),
1906
+ value: 0n,
1907
+ fallbackGas: TRUEO_MINT_FALLBACK_GAS
1908
+ });
1909
+ }
1910
+ const purposeText = args.purposeText.trim() || buildTrueoPurposePrefill({ action: "redeem", amountHuman: args.amountHuman, question: row.question });
1911
+ return finalizeTrueo({
1912
+ ...args,
1913
+ executorAddress: executor,
1914
+ purposeText,
1915
+ purposeSuffix: `Trueo: redeem on ${row.question || market}.`,
1916
+ steps
1917
+ });
1918
+ }
1919
+ function zeroForOneBuyOutcome(poolKey, tyd) {
1920
+ return viem.getAddress(poolKey.currency0) === viem.getAddress(tyd);
1921
+ }
1922
+ async function loadBetMarketAndPool(args) {
1923
+ const row = await fetchTrueoMarket({ marketAddress: args.marketAddress });
1924
+ assertTrueoBetCanCreate(row);
1925
+ const keys = await readTrueoPoolKeys({ rpcUrl: args.rpcUrl, marketAddress: viem.getAddress(args.marketAddress) });
1926
+ if (!keys) throw new Error("Could not read Trueo V2 pool keys. Confirm the market is Uniswap v4.");
1927
+ return { row, poolKey: args.side === "no" ? keys.no : keys.yes };
1928
+ }
1929
+ async function buildEvmMultisignBodyTrueoSwap(args) {
1930
+ assertTrueoChainId(args.chainId);
1931
+ const executor = viem.getAddress(args.executorAddress);
1932
+ const { row, poolKey } = await loadBetMarketAndPool({
1933
+ rpcUrl: args.rpcUrl,
1934
+ marketAddress: args.marketAddress,
1935
+ side: args.side
1936
+ });
1937
+ const amount = parseAmount(args.amountHuman, TRUEO_TYD_DECIMALS);
1938
+ const amountOutMin = args.amountOutMinimumHuman?.trim() ? viem.parseUnits(args.amountOutMinimumHuman.trim(), 18) : 0n;
1939
+ const steps = [];
1940
+ await pushApproveIfNeeded({
1941
+ steps,
1942
+ rpcUrl: args.rpcUrl,
1943
+ token: TRUEO_TYD,
1944
+ owner: executor,
1945
+ spender: TRUEO_PERMIT2,
1946
+ amount
1947
+ });
1948
+ steps.push({
1949
+ kind: "permit2_approve",
1950
+ to: TRUEO_PERMIT2,
1951
+ data: encodePermit2Approve({
1952
+ token: TRUEO_TYD,
1953
+ spender: TRUEO_UNIVERSAL_ROUTER_ADAPTER,
1954
+ amount,
1955
+ expiration: trueoPermit2Expiration()
1956
+ }),
1957
+ value: 0n,
1958
+ fallbackGas: TRUEO_APPROVE_FALLBACK_GAS
1959
+ });
1960
+ const encoded = encodeTrueoV4ExactInSwap({
1961
+ poolKey,
1962
+ zeroForOne: zeroForOneBuyOutcome(poolKey, TRUEO_TYD),
1963
+ amountIn: amount,
1964
+ amountOutMinimum: amountOutMin,
1965
+ recipient: executor,
1966
+ deadline: trueoSwapDeadline()
1967
+ });
1968
+ steps.push({
1969
+ kind: "swap",
1970
+ to: encoded.to,
1971
+ data: encoded.data,
1972
+ value: 0n,
1973
+ fallbackGas: TRUEO_SWAP_FALLBACK_GAS,
1974
+ routerSwap: true
1975
+ });
1976
+ const purposeText = args.purposeText.trim() || buildTrueoPurposePrefill({
1977
+ action: "swap",
1978
+ side: args.side,
1979
+ amountHuman: args.amountHuman,
1980
+ paymentSymbol: "TYD",
1981
+ question: row.question
1982
+ });
1983
+ return finalizeTrueo({
1984
+ ...args,
1985
+ executorAddress: executor,
1986
+ purposeText,
1987
+ purposeSuffix: `Trueo: buy ${args.side === "no" ? "No" : "Yes"} ${args.amountHuman} TYD.`,
1988
+ steps,
1989
+ betExtra: buildTrueoBetExtraJson({
1990
+ action: "swap",
1991
+ marketAddress: row.address,
1992
+ endOfTrading: row.endOfTrading
1993
+ })
1994
+ });
1995
+ }
1996
+ async function buildEvmMultisignBodyTrueoCreateOrder(args) {
1997
+ assertTrueoChainId(args.chainId);
1998
+ const executor = viem.getAddress(args.executorAddress);
1999
+ const { row, poolKey } = await loadBetMarketAndPool({
2000
+ rpcUrl: args.rpcUrl,
2001
+ marketAddress: args.marketAddress,
2002
+ side: args.side
2003
+ });
2004
+ const amount = parseAmount(args.amountHuman, TRUEO_TYD_DECIMALS);
2005
+ const steps = [];
2006
+ await pushApproveIfNeeded({
2007
+ steps,
2008
+ rpcUrl: args.rpcUrl,
2009
+ token: TRUEO_TYD,
2010
+ owner: executor,
2011
+ spender: TRUEO_PERMIT2,
2012
+ amount
2013
+ });
2014
+ steps.push({
2015
+ kind: "permit2_approve",
2016
+ to: TRUEO_PERMIT2,
2017
+ data: encodePermit2Approve({
2018
+ token: TRUEO_TYD,
2019
+ spender: TRUEO_ORDER_MANAGER,
2020
+ amount,
2021
+ expiration: trueoPermit2Expiration()
2022
+ }),
2023
+ value: 0n,
2024
+ fallbackGas: TRUEO_APPROVE_FALLBACK_GAS
2025
+ });
2026
+ steps.push({
2027
+ kind: "createOrder",
2028
+ to: TRUEO_ORDER_MANAGER,
2029
+ data: encodeTrueoCreateOrder({
2030
+ poolKey,
2031
+ amountIn: amount,
2032
+ tickLower: args.tickLower,
2033
+ tickUpper: args.tickUpper,
2034
+ zeroForOne: zeroForOneBuyOutcome(poolKey, TRUEO_TYD),
2035
+ enablePartialFill: args.enablePartialFill !== false
2036
+ }),
2037
+ value: 0n,
2038
+ fallbackGas: TRUEO_ORDER_FALLBACK_GAS
2039
+ });
2040
+ const purposeText = args.purposeText.trim() || buildTrueoPurposePrefill({
2041
+ action: "createOrder",
2042
+ side: args.side,
2043
+ amountHuman: args.amountHuman,
2044
+ question: row.question
2045
+ });
2046
+ return finalizeTrueo({
2047
+ ...args,
2048
+ executorAddress: executor,
2049
+ purposeText,
2050
+ purposeSuffix: `Trueo: limit ${args.side === "no" ? "No" : "Yes"} ${args.amountHuman} TYD.`,
2051
+ steps,
2052
+ betExtra: buildTrueoBetExtraJson({
2053
+ action: "createOrder",
2054
+ marketAddress: row.address,
2055
+ endOfTrading: row.endOfTrading
2056
+ })
2057
+ });
2058
+ }
2059
+ async function buildEvmMultisignBodyTrueoCancelOrder(args) {
2060
+ assertTrueoChainId(args.chainId);
2061
+ const executor = viem.getAddress(args.executorAddress);
2062
+ const row = await fetchTrueoMarket({ marketAddress: args.marketAddress });
2063
+ const keys = await readTrueoPoolKeys({ rpcUrl: args.rpcUrl, marketAddress: viem.getAddress(args.marketAddress) });
2064
+ if (!keys) throw new Error("Could not read Trueo V2 pool keys.");
2065
+ const poolKey = args.side === "no" ? keys.no : keys.yes;
2066
+ const steps = [
2067
+ {
2068
+ kind: "cancelOrder",
2069
+ to: TRUEO_ORDER_MANAGER,
2070
+ data: encodeTrueoCancelOrder({ poolKey, orderId: args.orderId }),
2071
+ value: 0n,
2072
+ fallbackGas: TRUEO_ORDER_FALLBACK_GAS
2073
+ }
2074
+ ];
2075
+ const purposeText = args.purposeText.trim() || buildTrueoPurposePrefill({ action: "cancelOrder", question: row.question });
2076
+ return finalizeTrueo({
2077
+ ...args,
2078
+ executorAddress: executor,
2079
+ purposeText,
2080
+ purposeSuffix: `Trueo: cancel order ${args.orderId}.`,
2081
+ steps
2082
+ });
2083
+ }
2084
+
2085
+ // src/protocols/evm/trueo/index.ts
2086
+ var trueoProtocolModule = {
2087
+ id: TRUEO_PROTOCOL_ID,
2088
+ chainCategory: "evm",
2089
+ isChainSupported(ctx) {
2090
+ const id = typeof ctx.chainId === "string" ? Number(ctx.chainId) : ctx.chainId;
2091
+ return ctx.chainCategory === "evm" && isTrueoChainSupported(id);
2092
+ },
2093
+ isTokenSupported(token) {
2094
+ return token.category === "evm" && (token.kind === "erc20" || token.kind === "ctmerc20");
2095
+ },
2096
+ actions: [
2097
+ {
2098
+ id: "trueo.wrap-tyd",
2099
+ protocolId: TRUEO_PROTOCOL_ID,
2100
+ chainCategory: "evm",
2101
+ description: "Mint TYD by depositing Base USDC into the Yearn ERC-4626 vault",
2102
+ commonParams: ["keyGen", "purposeText", "useCustomGas"],
2103
+ params: {}
2104
+ },
2105
+ {
2106
+ id: "trueo.unwrap-tyd",
2107
+ protocolId: TRUEO_PROTOCOL_ID,
2108
+ chainCategory: "evm",
2109
+ description: "Redeem TYD shares back to Base USDC",
2110
+ commonParams: ["keyGen", "purposeText", "useCustomGas"],
2111
+ params: {}
2112
+ },
2113
+ {
2114
+ id: "trueo.mint",
2115
+ protocolId: TRUEO_PROTOCOL_ID,
2116
+ chainCategory: "evm",
2117
+ description: "Mint YES+NO from TYD (or USDC via adapter)",
2118
+ commonParams: ["keyGen", "purposeText", "useCustomGas"],
2119
+ params: {}
2120
+ },
2121
+ {
2122
+ id: "trueo.burn",
2123
+ protocolId: TRUEO_PROTOCOL_ID,
2124
+ chainCategory: "evm",
2125
+ description: "Burn equal YES+NO back to TYD",
2126
+ commonParams: ["keyGen", "purposeText", "useCustomGas"],
2127
+ params: {}
2128
+ },
2129
+ {
2130
+ id: "trueo.redeem",
2131
+ protocolId: TRUEO_PROTOCOL_ID,
2132
+ chainCategory: "evm",
2133
+ description: "Redeem winning outcome tokens after resolution",
2134
+ commonParams: ["keyGen", "purposeText", "useCustomGas"],
2135
+ params: {}
2136
+ },
2137
+ {
2138
+ id: "trueo.swap",
2139
+ protocolId: TRUEO_PROTOCOL_ID,
2140
+ chainCategory: "evm",
2141
+ description: "Buy Yes or No with TYD via UniversalRouterAdapter V4 swap",
2142
+ commonParams: ["keyGen", "purposeText", "useCustomGas"],
2143
+ params: {}
2144
+ },
2145
+ {
2146
+ id: "trueo.create-order",
2147
+ protocolId: TRUEO_PROTOCOL_ID,
2148
+ chainCategory: "evm",
2149
+ description: "Create an on-chain OrderManager limit order",
2150
+ commonParams: ["keyGen", "purposeText", "useCustomGas"],
2151
+ params: {}
2152
+ },
2153
+ {
2154
+ id: "trueo.cancel-order",
2155
+ protocolId: TRUEO_PROTOCOL_ID,
2156
+ chainCategory: "evm",
2157
+ description: "Cancel an on-chain OrderManager order",
2158
+ commonParams: ["keyGen", "purposeText", "useCustomGas"],
2159
+ params: {}
2160
+ }
2161
+ ]
2162
+ };
2163
+ registerProtocolModule(trueoProtocolModule);
2164
+
2165
+ exports.PREDICTION_MARKETS_PROTOCOL_ID = PREDICTION_MARKETS_PROTOCOL_ID;
2166
+ exports.PREDICTION_MARKET_V1_KIND = PREDICTION_MARKET_V1_KIND;
2167
+ exports.TRUEO_API_ORIGIN = TRUEO_API_ORIGIN;
2168
+ exports.TRUEO_APPROVE_FALLBACK_GAS = TRUEO_APPROVE_FALLBACK_GAS;
2169
+ exports.TRUEO_BASE_CHAIN_ID = TRUEO_BASE_CHAIN_ID;
2170
+ exports.TRUEO_BET_ACTIONS = TRUEO_BET_ACTIONS;
2171
+ exports.TRUEO_BET_CLOSE_BUFFER_SECONDS = TRUEO_BET_CLOSE_BUFFER_SECONDS;
2172
+ exports.TRUEO_BET_CLOSE_ERROR = TRUEO_BET_CLOSE_ERROR;
2173
+ exports.TRUEO_BET_EXPIRED_ERROR = TRUEO_BET_EXPIRED_ERROR;
2174
+ exports.TRUEO_CHAIN_IDS = TRUEO_CHAIN_IDS;
2175
+ exports.TRUEO_CHANCE_SERIES_LOOKBACK_SECONDS = TRUEO_CHANCE_SERIES_LOOKBACK_SECONDS;
2176
+ exports.TRUEO_CHANCE_SERIES_RESOLUTION = TRUEO_CHANCE_SERIES_RESOLUTION;
2177
+ exports.TRUEO_MARKET_API_PREFIX = TRUEO_MARKET_API_PREFIX;
2178
+ exports.TRUEO_MARKET_PAGE_SIZE = TRUEO_MARKET_PAGE_SIZE;
2179
+ exports.TRUEO_MINT_FALLBACK_GAS = TRUEO_MINT_FALLBACK_GAS;
2180
+ exports.TRUEO_NETWORK = TRUEO_NETWORK;
2181
+ exports.TRUEO_ORDER_FALLBACK_GAS = TRUEO_ORDER_FALLBACK_GAS;
2182
+ exports.TRUEO_ORDER_MANAGER = TRUEO_ORDER_MANAGER;
2183
+ exports.TRUEO_OUTCOME_TOKEN_DECIMALS = TRUEO_OUTCOME_TOKEN_DECIMALS;
2184
+ exports.TRUEO_PERMIT2 = TRUEO_PERMIT2;
2185
+ exports.TRUEO_PERMIT2_APPROVAL_SECONDS = TRUEO_PERMIT2_APPROVAL_SECONDS;
2186
+ exports.TRUEO_PROTOCOL_ID = TRUEO_PROTOCOL_ID;
2187
+ exports.TRUEO_RECENT_MARKET_WINDOW_SECONDS = TRUEO_RECENT_MARKET_WINDOW_SECONDS;
2188
+ exports.TRUEO_SANE_IMPLIED_PRICE_MAX = TRUEO_SANE_IMPLIED_PRICE_MAX;
2189
+ exports.TRUEO_SWAP_FALLBACK_GAS = TRUEO_SWAP_FALLBACK_GAS;
2190
+ exports.TRUEO_TRENDING_MAX_LIMIT = TRUEO_TRENDING_MAX_LIMIT;
2191
+ exports.TRUEO_TRUE = TRUEO_TRUE;
2192
+ exports.TRUEO_TRUTH_MARKET_ADAPTER = TRUEO_TRUTH_MARKET_ADAPTER;
2193
+ exports.TRUEO_TRUTH_MARKET_MANAGER = TRUEO_TRUTH_MARKET_MANAGER;
2194
+ exports.TRUEO_TYD = TRUEO_TYD;
2195
+ exports.TRUEO_TYD_DECIMALS = TRUEO_TYD_DECIMALS;
2196
+ exports.TRUEO_TYD_VAULT_FALLBACK_GAS = TRUEO_TYD_VAULT_FALLBACK_GAS;
2197
+ exports.TRUEO_UNIVERSAL_ROUTER_ADAPTER = TRUEO_UNIVERSAL_ROUTER_ADAPTER;
2198
+ exports.TRUEO_USDC = TRUEO_USDC;
2199
+ exports.TRUEO_V4_HOOK = TRUEO_V4_HOOK;
2200
+ exports.UR_COMMAND_V4_SWAP = UR_COMMAND_V4_SWAP;
2201
+ exports.V4_ACTION_SETTLE = V4_ACTION_SETTLE;
2202
+ exports.V4_ACTION_SWAP_EXACT_IN_SINGLE = V4_ACTION_SWAP_EXACT_IN_SINGLE;
2203
+ exports.V4_ACTION_TAKE = V4_ACTION_TAKE;
2204
+ exports.applyTrueoMarketSearchScope = applyTrueoMarketSearchScope;
2205
+ exports.assertTrueoBetCanCreate = assertTrueoBetCanCreate;
2206
+ exports.assertTrueoBetCanExecute = assertTrueoBetCanExecute;
2207
+ exports.assertTrueoBetStillOpen = assertTrueoBetStillOpen;
2208
+ exports.assertTrueoChainId = assertTrueoChainId;
2209
+ exports.buildEvmMultisignBodyTrueoBurn = buildEvmMultisignBodyTrueoBurn;
2210
+ exports.buildEvmMultisignBodyTrueoCancelOrder = buildEvmMultisignBodyTrueoCancelOrder;
2211
+ exports.buildEvmMultisignBodyTrueoCreateOrder = buildEvmMultisignBodyTrueoCreateOrder;
2212
+ exports.buildEvmMultisignBodyTrueoMint = buildEvmMultisignBodyTrueoMint;
2213
+ exports.buildEvmMultisignBodyTrueoRedeem = buildEvmMultisignBodyTrueoRedeem;
2214
+ exports.buildEvmMultisignBodyTrueoSwap = buildEvmMultisignBodyTrueoSwap;
2215
+ exports.buildEvmMultisignBodyTrueoUnwrapTyd = buildEvmMultisignBodyTrueoUnwrapTyd;
2216
+ exports.buildEvmMultisignBodyTrueoWrapTyd = buildEvmMultisignBodyTrueoWrapTyd;
2217
+ exports.buildPredictionMarketEnvelope = buildPredictionMarketEnvelope;
2218
+ exports.buildTrueoBetExtraJson = buildTrueoBetExtraJson;
2219
+ exports.buildTrueoPurposePrefill = buildTrueoPurposePrefill;
2220
+ exports.encodeErc20Approve = encodeErc20Approve;
2221
+ exports.encodePermit2Approve = encodePermit2Approve;
2222
+ exports.encodeTrueoAdapterBurn = encodeTrueoAdapterBurn;
2223
+ exports.encodeTrueoAdapterMint = encodeTrueoAdapterMint;
2224
+ exports.encodeTrueoAdapterRedeem = encodeTrueoAdapterRedeem;
2225
+ exports.encodeTrueoBurn = encodeTrueoBurn;
2226
+ exports.encodeTrueoCancelOrder = encodeTrueoCancelOrder;
2227
+ exports.encodeTrueoCreateOrder = encodeTrueoCreateOrder;
2228
+ exports.encodeTrueoMint = encodeTrueoMint;
2229
+ exports.encodeTrueoRedeem = encodeTrueoRedeem;
2230
+ exports.encodeTrueoTydDeposit = encodeTrueoTydDeposit;
2231
+ exports.encodeTrueoTydRedeem = encodeTrueoTydRedeem;
2232
+ exports.encodeTrueoUniversalRouterExecute = encodeTrueoUniversalRouterExecute;
2233
+ exports.encodeTrueoV4ExactInInput = encodeTrueoV4ExactInInput;
2234
+ exports.encodeTrueoV4ExactInSwap = encodeTrueoV4ExactInSwap;
2235
+ exports.extraJsonFromSignRequest = extraJsonFromSignRequest;
2236
+ exports.fetchTrueoCategories = fetchTrueoCategories;
2237
+ exports.fetchTrueoChanceSeries = fetchTrueoChanceSeries;
2238
+ exports.fetchTrueoMarket = fetchTrueoMarket;
2239
+ exports.fetchTrueoOhlc = fetchTrueoOhlc;
2240
+ exports.fetchTrueoOrderbook = fetchTrueoOrderbook;
2241
+ exports.fetchTrueoTransactions = fetchTrueoTransactions;
2242
+ exports.fetchTrueoTrending = fetchTrueoTrending;
2243
+ exports.filterTrueoMarkets = filterTrueoMarkets;
2244
+ exports.getPredictionMarketSummary = getPredictionMarketSummary;
2245
+ exports.isTrueoBetAction = isTrueoBetAction;
2246
+ exports.isTrueoChainSupported = isTrueoChainSupported;
2247
+ exports.isTrueoCoreToken = isTrueoCoreToken;
2248
+ exports.isTrueoMarketLiveOrRecent = isTrueoMarketLiveOrRecent;
2249
+ exports.isTrueoMarketTradingOpen = isTrueoMarketTradingOpen;
2250
+ exports.isTrueoOutcomeTokenLabel = isTrueoOutcomeTokenLabel;
2251
+ exports.listMyPredictionMarketsSummary = listMyPredictionMarketsSummary;
2252
+ exports.listPredictionMarketsForHoldings = listPredictionMarketsForHoldings;
2253
+ exports.listTrueoMarketsPage = listTrueoMarketsPage;
2254
+ exports.normalizeTrueoAddress = normalizeTrueoAddress;
2255
+ exports.normalizeTrueoMarketRow = normalizeTrueoMarketRow;
2256
+ exports.normalizeTrueoOhlcResolution = normalizeTrueoOhlcResolution;
2257
+ exports.outcomeTokensFromMarkets = outcomeTokensFromMarkets;
2258
+ exports.parseTrueoBetExtraJson = parseTrueoBetExtraJson;
2259
+ exports.preferOpenTrueoTitleMatches = preferOpenTrueoTitleMatches;
2260
+ exports.readTrueoPoolKeys = readTrueoPoolKeys;
2261
+ exports.searchPredictionMarkets = searchPredictionMarkets;
2262
+ exports.searchPredictionMarketsSummary = searchPredictionMarketsSummary;
2263
+ exports.searchTrueoMarkets = searchTrueoMarkets;
2264
+ exports.searchTrueoMarketsPage = searchTrueoMarketsPage;
2265
+ exports.suggestTrueoTokensToAdd = suggestTrueoTokensToAdd;
2266
+ exports.trueoAdapterMintAbi = trueoAdapterMintAbi;
2267
+ exports.trueoBetCreateBlockedReason = trueoBetCreateBlockedReason;
2268
+ exports.trueoBetExecuteBlockedReason = trueoBetExecuteBlockedReason;
2269
+ exports.trueoCompactVolumeLabel = trueoCompactVolumeLabel;
2270
+ exports.trueoErc20Abi = trueoErc20Abi;
2271
+ exports.trueoExpiresAtIso = trueoExpiresAtIso;
2272
+ exports.trueoExpiresAtLabel = trueoExpiresAtLabel;
2273
+ exports.trueoFetchCategoriesSummary = trueoFetchCategoriesSummary;
2274
+ exports.trueoFetchChanceSeriesSummary = trueoFetchChanceSeriesSummary;
2275
+ exports.trueoFetchMarketSummary = trueoFetchMarketSummary;
2276
+ exports.trueoFetchOrderbookSummary = trueoFetchOrderbookSummary;
2277
+ exports.trueoFetchTrendingSummary = trueoFetchTrendingSummary;
2278
+ exports.trueoHoldingTokenAddressesFromRegistry = trueoHoldingTokenAddressesFromRegistry;
2279
+ exports.trueoImpliedPriceFromSqrtX96 = trueoImpliedPriceFromSqrtX96;
2280
+ exports.trueoIsSaneImpliedPrice = trueoIsSaneImpliedPrice;
2281
+ exports.trueoJsonFetch = trueoJsonFetch;
2282
+ exports.trueoListUsesTrending = trueoListUsesTrending;
2283
+ exports.trueoMarketAbi = trueoMarketAbi;
2284
+ exports.trueoMarketApiPath = trueoMarketApiPath;
2285
+ exports.trueoMarketStatusLabel = trueoMarketStatusLabel;
2286
+ exports.trueoMarketToPredictionRow = trueoMarketToPredictionRow;
2287
+ exports.trueoMarketV2Abi = trueoMarketV2Abi;
2288
+ exports.trueoMarketVotingOpen = trueoMarketVotingOpen;
2289
+ exports.trueoOrderManagerAbi = trueoOrderManagerAbi;
2290
+ exports.trueoOrderManagerStructAbi = trueoOrderManagerStructAbi;
2291
+ exports.trueoPercentLabel = trueoPercentLabel;
2292
+ exports.trueoPermit2ApproveAbi = trueoPermit2ApproveAbi;
2293
+ exports.trueoPermit2Expiration = trueoPermit2Expiration;
2294
+ exports.trueoProtocolModule = trueoProtocolModule;
2295
+ exports.trueoQueryTokens = trueoQueryTokens;
2296
+ exports.trueoResolutionCopy = trueoResolutionCopy;
2297
+ exports.trueoResolvedSide = trueoResolvedSide;
2298
+ exports.trueoSanitizeBinaryPrices = trueoSanitizeBinaryPrices;
2299
+ exports.trueoSearchMarketsSummary = trueoSearchMarketsSummary;
2300
+ exports.trueoSearchScopeNote = trueoSearchScopeNote;
2301
+ exports.trueoSwapDeadline = trueoSwapDeadline;
2302
+ exports.trueoTimeUntilTradingEndsLabel = trueoTimeUntilTradingEndsLabel;
2303
+ exports.trueoTradingDeadlineLabel = trueoTradingDeadlineLabel;
2304
+ exports.trueoTradingEndsCopy = trueoTradingEndsCopy;
2305
+ exports.trueoTydVaultAbi = trueoTydVaultAbi;
2306
+ exports.trueoUniversalRouterAdapterAbi = trueoUniversalRouterAdapterAbi;
2307
+ //# sourceMappingURL=index.cjs.map
2308
+ //# sourceMappingURL=index.cjs.map