@blockrun/clawrouter 0.12.263 → 0.12.264

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.
Files changed (3) hide show
  1. package/dist/cli.js +168 -80
  2. package/dist/index.js +157 -75
  3. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -117032,6 +117032,35 @@ var init_client5 = __esm({
117032
117032
  }
117033
117033
  });
117034
117034
 
117035
+ // src/polymarket/spend-policy.ts
117036
+ function resolveSpendControl(deps) {
117037
+ if (deps?.spendControl) return deps.spendControl;
117038
+ defaultControl ??= new SpendControl();
117039
+ return defaultControl;
117040
+ }
117041
+ function usdToMicros(usd) {
117042
+ return String(Math.ceil(usd * 1e6));
117043
+ }
117044
+ async function signUnderSpendPolicy(deps, quote, action, sign4) {
117045
+ const control = resolveSpendControl(deps);
117046
+ const reservation = assertSpendPolicyAllows(control, quote);
117047
+ try {
117048
+ const signed2 = await sign4();
117049
+ if (reservation !== void 0) control.settleReservation(reservation, { action });
117050
+ return signed2;
117051
+ } catch (err) {
117052
+ if (reservation !== void 0) control.releaseReservation(reservation);
117053
+ throw err;
117054
+ }
117055
+ }
117056
+ var defaultControl;
117057
+ var init_spend_policy = __esm({
117058
+ "src/polymarket/spend-policy.ts"() {
117059
+ "use strict";
117060
+ init_spend_control();
117061
+ }
117062
+ });
117063
+
117035
117064
  // src/polymarket/orders.ts
117036
117065
  function getSessionLedger() {
117037
117066
  return {
@@ -117100,6 +117129,9 @@ function isCredsMismatchError(err) {
117100
117129
  return msg.includes("unauthorized") || msg.includes("api key not found") || msg.includes("invalid api key");
117101
117130
  }
117102
117131
  async function mapClobError(err) {
117132
+ if (err instanceof SpendPolicyError) {
117133
+ return `Refused by spend policy \u2014 nothing was signed. ${err.message} (see ~/.openclaw/blockrun/spending.json)`;
117134
+ }
117103
117135
  const e7 = err;
117104
117136
  const dataText = e7?.data ? ` \u2014 ${typeof e7.data === "string" ? e7.data : JSON.stringify(e7.data)}` : "";
117105
117137
  const message = `${e7?.message ?? String(err)}${dataText}`;
@@ -117146,7 +117178,7 @@ async function withCredsRetry(fn) {
117146
117178
  return fn(fresh);
117147
117179
  }
117148
117180
  }
117149
- async function executeTrade(input) {
117181
+ async function executeTrade(input, deps) {
117150
117182
  const side = input.action === "buy" ? Side.BUY : Side.SELL;
117151
117183
  const isLimit = input.price !== void 0;
117152
117184
  if (isLimit && input.size === void 0) {
@@ -117158,6 +117190,18 @@ async function executeTrade(input) {
117158
117190
  isError: true
117159
117191
  };
117160
117192
  }
117193
+ if (!isLimit && input.action === "buy" && input.amount_usd !== void 0 && !(Number.isFinite(input.amount_usd) && input.amount_usd > 0)) {
117194
+ return {
117195
+ text: `amount_usd must be a positive dollar amount to spend, got ${input.amount_usd}.`,
117196
+ isError: true
117197
+ };
117198
+ }
117199
+ if (isLimit && input.size !== void 0 && !(Number.isFinite(input.size) && input.size > 0)) {
117200
+ return {
117201
+ text: `size must be a positive number of shares, got ${input.size}.`,
117202
+ isError: true
117203
+ };
117204
+ }
117161
117205
  if (!isLimit && input.action === "sell" && input.size === void 0) {
117162
117206
  return { text: `Market sells need size (shares to sell).`, isError: true };
117163
117207
  }
@@ -117257,39 +117301,44 @@ Re-call with confirm:true to sign and submit.`,
117257
117301
  }
117258
117302
  const options = { tickSize, negRisk };
117259
117303
  reserveBet(notional, input.agent_id);
117260
- let response;
117304
+ const policyQuote = {
117305
+ payTo: negRisk ? NEG_RISK_CTF_EXCHANGE_V2 : CTF_EXCHANGE_V2,
117306
+ network: `eip155:${POLYGON_CHAIN_ID}`,
117307
+ asset: PUSD_COLLATERAL,
117308
+ amount: usdToMicros(notional)
117309
+ };
117310
+ let r2;
117261
117311
  try {
117262
- response = isLimit ? await clob.createAndPostOrder(
117263
- {
117264
- tokenID: token.tokenId,
117265
- price,
117266
- size: size5,
117267
- side,
117268
- ...orderKind === "GTD" && input.expires_at ? { expiration: input.expires_at } : {}
117269
- },
117270
- options,
117271
- orderKind === "GTD" ? OrderType.GTD : OrderType.GTC,
117272
- input.post_only ?? false
117273
- ) : await clob.createAndPostMarketOrder(
117274
- {
117275
- tokenID: token.tokenId,
117276
- amount: input.action === "buy" ? input.amount_usd : size5,
117277
- side,
117278
- orderType: orderKind === "FAK" ? OrderType.FAK : OrderType.FOK
117279
- },
117280
- options,
117281
- orderKind === "FAK" ? OrderType.FAK : OrderType.FOK
117282
- );
117312
+ r2 = await signUnderSpendPolicy(deps, policyQuote, "polymarket order", async () => {
117313
+ const res = await (isLimit ? clob.createAndPostOrder(
117314
+ {
117315
+ tokenID: token.tokenId,
117316
+ price,
117317
+ size: size5,
117318
+ side,
117319
+ ...orderKind === "GTD" && input.expires_at ? { expiration: input.expires_at } : {}
117320
+ },
117321
+ options,
117322
+ orderKind === "GTD" ? OrderType.GTD : OrderType.GTC,
117323
+ input.post_only ?? false
117324
+ ) : clob.createAndPostMarketOrder(
117325
+ {
117326
+ tokenID: token.tokenId,
117327
+ amount: input.action === "buy" ? input.amount_usd : size5,
117328
+ side,
117329
+ orderType: orderKind === "FAK" ? OrderType.FAK : OrderType.FOK
117330
+ },
117331
+ options,
117332
+ orderKind === "FAK" ? OrderType.FAK : OrderType.FOK
117333
+ ));
117334
+ const placed = res?.success !== false && (res?.orderID || res?.status === "matched");
117335
+ if (!placed) throw new Error(res?.errorMsg || "order rejected");
117336
+ return res;
117337
+ });
117283
117338
  } catch (submitErr) {
117284
117339
  releaseBet(notional, input.agent_id);
117285
117340
  throw submitErr;
117286
117341
  }
117287
- const r2 = response;
117288
- const placed = r2?.success !== false && (r2?.orderID || r2?.status === "matched");
117289
- if (!placed) {
117290
- releaseBet(notional, input.agent_id);
117291
- throw new Error(r2?.errorMsg || "order rejected");
117292
- }
117293
117342
  commitBet();
117294
117343
  const filled = r2?.status === "matched" || (r2?.transactionsHashes?.length ?? 0) > 0;
117295
117344
  return {
@@ -117378,6 +117427,8 @@ var init_orders = __esm({
117378
117427
  init_client5();
117379
117428
  init_constants3();
117380
117429
  init_creds();
117430
+ init_spend_control();
117431
+ init_spend_policy();
117381
117432
  ledger = {
117382
117433
  totalUsd: 0,
117383
117434
  count: 0,
@@ -225312,7 +225363,7 @@ var init_setup = __esm({
225312
225363
  });
225313
225364
 
225314
225365
  // src/polymarket/redeem.ts
225315
- async function redeemPosition(input) {
225366
+ async function redeemPosition(input, deps) {
225316
225367
  if (!input.condition_id) {
225317
225368
  return {
225318
225369
  text: `Pass condition_id:"0x\u2026" (see action:"positions" for redeemable markets).`,
@@ -225388,20 +225439,31 @@ async function redeemPosition(input) {
225388
225439
  ]
225389
225440
  });
225390
225441
  const target = negRisk ? NEG_RISK_ADAPTER : CONDITIONAL_TOKENS;
225391
- let txHash;
225392
- if (getSigType() === 3) {
225393
- const res = await sendWalletBatch([{ target, value: "0", data }], owner, "Redeem");
225394
- txHash = res.transactionHash;
225395
- } else {
225396
- const account = getPolymarketAccount();
225397
- const wallet = createWalletClient({
225398
- account,
225399
- chain: polygon,
225400
- transport: http(POLYGON_RPC_URLS[0])
225401
- });
225402
- txHash = await wallet.sendTransaction({ to: target, data, chain: polygon, account });
225403
- await pc.waitForTransactionReceipt({ hash: txHash });
225404
- }
225442
+ const eoa = getSigType() !== 3;
225443
+ const txHash = await signUnderSpendPolicy(
225444
+ deps,
225445
+ {
225446
+ payTo: target,
225447
+ network: `eip155:${POLYGON_CHAIN_ID}`,
225448
+ asset: PUSD_COLLATERAL,
225449
+ amount: "0"
225450
+ },
225451
+ "polymarket redeem",
225452
+ async () => {
225453
+ if (!eoa) {
225454
+ const res = await sendWalletBatch([{ target, value: "0", data }], owner, "Redeem");
225455
+ return res.transactionHash;
225456
+ }
225457
+ const account = getPolymarketAccount();
225458
+ const wallet = createWalletClient({
225459
+ account,
225460
+ chain: polygon,
225461
+ transport: http(POLYGON_RPC_URLS[0])
225462
+ });
225463
+ return wallet.sendTransaction({ to: target, data, chain: polygon, account });
225464
+ }
225465
+ );
225466
+ if (eoa) await pc.waitForTransactionReceipt({ hash: txHash });
225405
225467
  const balanceAfter = await getPusdBalance(owner).catch(() => null);
225406
225468
  return {
225407
225469
  text: [
@@ -225432,6 +225494,7 @@ var init_redeem = __esm({
225432
225494
  init_positions();
225433
225495
  init_relayer();
225434
225496
  init_setup();
225497
+ init_spend_policy();
225435
225498
  }
225436
225499
  });
225437
225500
 
@@ -225444,7 +225507,13 @@ async function rawPusdBalance(owner) {
225444
225507
  args: [owner]
225445
225508
  });
225446
225509
  }
225447
- async function withdrawFunds(input) {
225510
+ async function withdrawFunds(input, deps) {
225511
+ if (input.amount_usd !== void 0 && !(Number.isFinite(input.amount_usd) && input.amount_usd > 0)) {
225512
+ return {
225513
+ text: `amount_usd must be a positive dollar amount, got ${input.amount_usd}. Omit it to withdraw the full balance.`,
225514
+ isError: true
225515
+ };
225516
+ }
225448
225517
  let owner;
225449
225518
  try {
225450
225519
  owner = getFundsAddress();
@@ -225515,29 +225584,40 @@ async function withdrawFunds(input) {
225515
225584
  functionName: "transfer",
225516
225585
  args: [bridgeEvm, amountRaw]
225517
225586
  });
225518
- let txHash;
225519
- if (getSigType() === 3) {
225520
- const res = await sendWalletBatch(
225521
- [{ target: PUSD_COLLATERAL, value: "0", data }],
225522
- owner,
225523
- "Withdraw"
225524
- );
225525
- txHash = res.transactionHash;
225526
- } else {
225527
- const account = getPolymarketAccount();
225528
- const wallet = createWalletClient({
225529
- account,
225530
- chain: polygon,
225531
- transport: http(POLYGON_RPC_URLS[0])
225532
- });
225533
- txHash = await wallet.sendTransaction({
225534
- to: PUSD_COLLATERAL,
225535
- data,
225536
- chain: polygon,
225537
- account
225538
- });
225539
- await getPublicClient().waitForTransactionReceipt({ hash: txHash });
225540
- }
225587
+ const eoa = getSigType() !== 3;
225588
+ const txHash = await signUnderSpendPolicy(
225589
+ deps,
225590
+ {
225591
+ payTo: recipient,
225592
+ network: `eip155:${BASE_CHAIN_ID}`,
225593
+ asset: BASE_USDC,
225594
+ amount: amountRaw.toString()
225595
+ },
225596
+ "polymarket withdraw",
225597
+ async () => {
225598
+ if (!eoa) {
225599
+ const res = await sendWalletBatch(
225600
+ [{ target: PUSD_COLLATERAL, value: "0", data }],
225601
+ owner,
225602
+ "Withdraw"
225603
+ );
225604
+ return res.transactionHash;
225605
+ }
225606
+ const account = getPolymarketAccount();
225607
+ const wallet = createWalletClient({
225608
+ account,
225609
+ chain: polygon,
225610
+ transport: http(POLYGON_RPC_URLS[0])
225611
+ });
225612
+ return wallet.sendTransaction({
225613
+ to: PUSD_COLLATERAL,
225614
+ data,
225615
+ chain: polygon,
225616
+ account
225617
+ });
225618
+ }
225619
+ );
225620
+ if (eoa) await getPublicClient().waitForTransactionReceipt({ hash: txHash });
225541
225621
  return {
225542
225622
  text: [
225543
225623
  `\u2705 Withdrawal submitted: $${amountUsd.toFixed(2)} pUSD \u2192 USDC on Base`,
@@ -225572,6 +225652,7 @@ var init_withdraw = __esm({
225572
225652
  init_positions();
225573
225653
  init_relayer();
225574
225654
  init_setup();
225655
+ init_spend_policy();
225575
225656
  }
225576
225657
  });
225577
225658
 
@@ -226217,7 +226298,7 @@ async function bridgeAddressFor(vault) {
226217
226298
  throw new Error(`Bridge did not return a deposit address (got: ${JSON.stringify(res.data)}).`);
226218
226299
  return evm;
226219
226300
  }
226220
- async function fundVault(input) {
226301
+ async function fundVault(input, deps) {
226221
226302
  if (input.amount_usd === void 0 || input.amount_usd <= 0) {
226222
226303
  return {
226223
226304
  text: `Pass amount_usd \u2014 the USDC amount to move from your Base wallet into your Polymarket vault (e.g. amount_usd:5).`,
@@ -226274,12 +226355,12 @@ async function fundVault(input) {
226274
226355
  }
226275
226356
  const privateKey = getOrCreateWalletKey();
226276
226357
  const amountMicro = String(Math.floor(amountUsd * 10 ** USDC_DECIMALS));
226277
- const depositAuthorization = await createPaymentPayload(
226278
- privateKey,
226279
- agent,
226280
- bridge,
226281
- amountMicro,
226282
- `eip155:${BASE_CHAIN_ID}`
226358
+ const network = `eip155:${BASE_CHAIN_ID}`;
226359
+ const depositAuthorization = await signUnderSpendPolicy(
226360
+ deps,
226361
+ { payTo: bridge, network, asset: BASE_USDC, amount: amountMicro },
226362
+ "polymarket fund",
226363
+ () => createPaymentPayload(privateKey, agent, bridge, amountMicro, network)
226283
226364
  );
226284
226365
  const client = new BlockrunClient({ privateKey });
226285
226366
  const result = await client.post("/v1/polymarket/fund", {
@@ -226329,6 +226410,7 @@ var init_fund = __esm({
226329
226410
  init_constants3();
226330
226411
  init_positions();
226331
226412
  init_setup();
226413
+ init_spend_policy();
226332
226414
  FUND_FEE_USD = 0.01;
226333
226415
  USDC_DECIMALS = 6;
226334
226416
  FUND_MIN_USD = Number(process.env.POLYMARKET_FUND_MIN_USD || "2");
@@ -228628,6 +228710,7 @@ init_balance();
228628
228710
  init_wallet2();
228629
228711
  init_stats();
228630
228712
  init_proxy();
228713
+ init_spend_control();
228631
228714
  init_version4();
228632
228715
  import { platform, arch, freemem, totalmem } from "os";
228633
228716
  import { existsSync as existsSync3, readFileSync as readFileSync3 } from "fs";
@@ -228894,6 +228977,15 @@ var DOCTOR_MODELS = {
228894
228977
  cost: "~$0.01"
228895
228978
  }
228896
228979
  };
228980
+ function createDoctorX402Client(opts) {
228981
+ const account = privateKeyToAccount(opts.walletKey);
228982
+ const publicClient = createPublicClient({ chain: base, transport: http() });
228983
+ const evmSigner = toClientEvmSigner(account, publicClient);
228984
+ const x402 = new x402Client();
228985
+ registerSpendPolicyHook(x402, opts.spendControl ?? new SpendControl());
228986
+ registerExactEvmScheme(x402, { signer: evmSigner });
228987
+ return x402;
228988
+ }
228897
228989
  async function analyzeWithAI(diagnostics, userQuestion, model = "sonnet") {
228898
228990
  if (diagnostics.wallet.isEmpty) {
228899
228991
  console.log("\n\u{1F4B3} Wallet is empty - cannot call AI for analysis.");
@@ -228911,11 +229003,7 @@ async function analyzeWithAI(diagnostics, userQuestion, model = "sonnet") {
228911
229003
  `);
228912
229004
  try {
228913
229005
  const { key: key2 } = await resolveOrGenerateWalletKey();
228914
- const account = privateKeyToAccount(key2);
228915
- const publicClient = createPublicClient({ chain: base, transport: http() });
228916
- const evmSigner = toClientEvmSigner(account, publicClient);
228917
- const x402 = new x402Client();
228918
- registerExactEvmScheme(x402, { signer: evmSigner });
229006
+ const x402 = createDoctorX402Client({ walletKey: key2 });
228919
229007
  const paymentChain = diagnostics.wallet.paymentChain;
228920
229008
  if (paymentChain === "solana") {
228921
229009
  try {
package/dist/index.js CHANGED
@@ -116851,6 +116851,35 @@ var init_client5 = __esm({
116851
116851
  }
116852
116852
  });
116853
116853
 
116854
+ // src/polymarket/spend-policy.ts
116855
+ function resolveSpendControl(deps) {
116856
+ if (deps?.spendControl) return deps.spendControl;
116857
+ defaultControl ??= new SpendControl();
116858
+ return defaultControl;
116859
+ }
116860
+ function usdToMicros(usd) {
116861
+ return String(Math.ceil(usd * 1e6));
116862
+ }
116863
+ async function signUnderSpendPolicy(deps, quote, action, sign4) {
116864
+ const control = resolveSpendControl(deps);
116865
+ const reservation = assertSpendPolicyAllows(control, quote);
116866
+ try {
116867
+ const signed2 = await sign4();
116868
+ if (reservation !== void 0) control.settleReservation(reservation, { action });
116869
+ return signed2;
116870
+ } catch (err) {
116871
+ if (reservation !== void 0) control.releaseReservation(reservation);
116872
+ throw err;
116873
+ }
116874
+ }
116875
+ var defaultControl;
116876
+ var init_spend_policy = __esm({
116877
+ "src/polymarket/spend-policy.ts"() {
116878
+ "use strict";
116879
+ init_spend_control();
116880
+ }
116881
+ });
116882
+
116854
116883
  // src/polymarket/orders.ts
116855
116884
  function getSessionLedger() {
116856
116885
  return {
@@ -116919,6 +116948,9 @@ function isCredsMismatchError(err) {
116919
116948
  return msg.includes("unauthorized") || msg.includes("api key not found") || msg.includes("invalid api key");
116920
116949
  }
116921
116950
  async function mapClobError(err) {
116951
+ if (err instanceof SpendPolicyError) {
116952
+ return `Refused by spend policy \u2014 nothing was signed. ${err.message} (see ~/.openclaw/blockrun/spending.json)`;
116953
+ }
116922
116954
  const e7 = err;
116923
116955
  const dataText = e7?.data ? ` \u2014 ${typeof e7.data === "string" ? e7.data : JSON.stringify(e7.data)}` : "";
116924
116956
  const message = `${e7?.message ?? String(err)}${dataText}`;
@@ -116965,7 +116997,7 @@ async function withCredsRetry(fn) {
116965
116997
  return fn(fresh);
116966
116998
  }
116967
116999
  }
116968
- async function executeTrade(input) {
117000
+ async function executeTrade(input, deps) {
116969
117001
  const side = input.action === "buy" ? Side.BUY : Side.SELL;
116970
117002
  const isLimit = input.price !== void 0;
116971
117003
  if (isLimit && input.size === void 0) {
@@ -116977,6 +117009,18 @@ async function executeTrade(input) {
116977
117009
  isError: true
116978
117010
  };
116979
117011
  }
117012
+ if (!isLimit && input.action === "buy" && input.amount_usd !== void 0 && !(Number.isFinite(input.amount_usd) && input.amount_usd > 0)) {
117013
+ return {
117014
+ text: `amount_usd must be a positive dollar amount to spend, got ${input.amount_usd}.`,
117015
+ isError: true
117016
+ };
117017
+ }
117018
+ if (isLimit && input.size !== void 0 && !(Number.isFinite(input.size) && input.size > 0)) {
117019
+ return {
117020
+ text: `size must be a positive number of shares, got ${input.size}.`,
117021
+ isError: true
117022
+ };
117023
+ }
116980
117024
  if (!isLimit && input.action === "sell" && input.size === void 0) {
116981
117025
  return { text: `Market sells need size (shares to sell).`, isError: true };
116982
117026
  }
@@ -117076,39 +117120,44 @@ Re-call with confirm:true to sign and submit.`,
117076
117120
  }
117077
117121
  const options = { tickSize, negRisk };
117078
117122
  reserveBet(notional, input.agent_id);
117079
- let response;
117123
+ const policyQuote = {
117124
+ payTo: negRisk ? NEG_RISK_CTF_EXCHANGE_V2 : CTF_EXCHANGE_V2,
117125
+ network: `eip155:${POLYGON_CHAIN_ID}`,
117126
+ asset: PUSD_COLLATERAL,
117127
+ amount: usdToMicros(notional)
117128
+ };
117129
+ let r2;
117080
117130
  try {
117081
- response = isLimit ? await clob.createAndPostOrder(
117082
- {
117083
- tokenID: token.tokenId,
117084
- price,
117085
- size: size5,
117086
- side,
117087
- ...orderKind === "GTD" && input.expires_at ? { expiration: input.expires_at } : {}
117088
- },
117089
- options,
117090
- orderKind === "GTD" ? OrderType.GTD : OrderType.GTC,
117091
- input.post_only ?? false
117092
- ) : await clob.createAndPostMarketOrder(
117093
- {
117094
- tokenID: token.tokenId,
117095
- amount: input.action === "buy" ? input.amount_usd : size5,
117096
- side,
117097
- orderType: orderKind === "FAK" ? OrderType.FAK : OrderType.FOK
117098
- },
117099
- options,
117100
- orderKind === "FAK" ? OrderType.FAK : OrderType.FOK
117101
- );
117131
+ r2 = await signUnderSpendPolicy(deps, policyQuote, "polymarket order", async () => {
117132
+ const res = await (isLimit ? clob.createAndPostOrder(
117133
+ {
117134
+ tokenID: token.tokenId,
117135
+ price,
117136
+ size: size5,
117137
+ side,
117138
+ ...orderKind === "GTD" && input.expires_at ? { expiration: input.expires_at } : {}
117139
+ },
117140
+ options,
117141
+ orderKind === "GTD" ? OrderType.GTD : OrderType.GTC,
117142
+ input.post_only ?? false
117143
+ ) : clob.createAndPostMarketOrder(
117144
+ {
117145
+ tokenID: token.tokenId,
117146
+ amount: input.action === "buy" ? input.amount_usd : size5,
117147
+ side,
117148
+ orderType: orderKind === "FAK" ? OrderType.FAK : OrderType.FOK
117149
+ },
117150
+ options,
117151
+ orderKind === "FAK" ? OrderType.FAK : OrderType.FOK
117152
+ ));
117153
+ const placed = res?.success !== false && (res?.orderID || res?.status === "matched");
117154
+ if (!placed) throw new Error(res?.errorMsg || "order rejected");
117155
+ return res;
117156
+ });
117102
117157
  } catch (submitErr) {
117103
117158
  releaseBet(notional, input.agent_id);
117104
117159
  throw submitErr;
117105
117160
  }
117106
- const r2 = response;
117107
- const placed = r2?.success !== false && (r2?.orderID || r2?.status === "matched");
117108
- if (!placed) {
117109
- releaseBet(notional, input.agent_id);
117110
- throw new Error(r2?.errorMsg || "order rejected");
117111
- }
117112
117161
  commitBet();
117113
117162
  const filled = r2?.status === "matched" || (r2?.transactionsHashes?.length ?? 0) > 0;
117114
117163
  return {
@@ -117197,6 +117246,8 @@ var init_orders = __esm({
117197
117246
  init_client5();
117198
117247
  init_constants3();
117199
117248
  init_creds();
117249
+ init_spend_control();
117250
+ init_spend_policy();
117200
117251
  ledger = {
117201
117252
  totalUsd: 0,
117202
117253
  count: 0,
@@ -225131,7 +225182,7 @@ var init_setup = __esm({
225131
225182
  });
225132
225183
 
225133
225184
  // src/polymarket/redeem.ts
225134
- async function redeemPosition(input) {
225185
+ async function redeemPosition(input, deps) {
225135
225186
  if (!input.condition_id) {
225136
225187
  return {
225137
225188
  text: `Pass condition_id:"0x\u2026" (see action:"positions" for redeemable markets).`,
@@ -225207,20 +225258,31 @@ async function redeemPosition(input) {
225207
225258
  ]
225208
225259
  });
225209
225260
  const target = negRisk ? NEG_RISK_ADAPTER : CONDITIONAL_TOKENS;
225210
- let txHash;
225211
- if (getSigType() === 3) {
225212
- const res = await sendWalletBatch([{ target, value: "0", data }], owner, "Redeem");
225213
- txHash = res.transactionHash;
225214
- } else {
225215
- const account = getPolymarketAccount();
225216
- const wallet = createWalletClient({
225217
- account,
225218
- chain: polygon,
225219
- transport: http(POLYGON_RPC_URLS[0])
225220
- });
225221
- txHash = await wallet.sendTransaction({ to: target, data, chain: polygon, account });
225222
- await pc.waitForTransactionReceipt({ hash: txHash });
225223
- }
225261
+ const eoa = getSigType() !== 3;
225262
+ const txHash = await signUnderSpendPolicy(
225263
+ deps,
225264
+ {
225265
+ payTo: target,
225266
+ network: `eip155:${POLYGON_CHAIN_ID}`,
225267
+ asset: PUSD_COLLATERAL,
225268
+ amount: "0"
225269
+ },
225270
+ "polymarket redeem",
225271
+ async () => {
225272
+ if (!eoa) {
225273
+ const res = await sendWalletBatch([{ target, value: "0", data }], owner, "Redeem");
225274
+ return res.transactionHash;
225275
+ }
225276
+ const account = getPolymarketAccount();
225277
+ const wallet = createWalletClient({
225278
+ account,
225279
+ chain: polygon,
225280
+ transport: http(POLYGON_RPC_URLS[0])
225281
+ });
225282
+ return wallet.sendTransaction({ to: target, data, chain: polygon, account });
225283
+ }
225284
+ );
225285
+ if (eoa) await pc.waitForTransactionReceipt({ hash: txHash });
225224
225286
  const balanceAfter = await getPusdBalance(owner).catch(() => null);
225225
225287
  return {
225226
225288
  text: [
@@ -225251,6 +225313,7 @@ var init_redeem = __esm({
225251
225313
  init_positions();
225252
225314
  init_relayer();
225253
225315
  init_setup();
225316
+ init_spend_policy();
225254
225317
  }
225255
225318
  });
225256
225319
 
@@ -225263,7 +225326,13 @@ async function rawPusdBalance(owner) {
225263
225326
  args: [owner]
225264
225327
  });
225265
225328
  }
225266
- async function withdrawFunds(input) {
225329
+ async function withdrawFunds(input, deps) {
225330
+ if (input.amount_usd !== void 0 && !(Number.isFinite(input.amount_usd) && input.amount_usd > 0)) {
225331
+ return {
225332
+ text: `amount_usd must be a positive dollar amount, got ${input.amount_usd}. Omit it to withdraw the full balance.`,
225333
+ isError: true
225334
+ };
225335
+ }
225267
225336
  let owner;
225268
225337
  try {
225269
225338
  owner = getFundsAddress();
@@ -225334,29 +225403,40 @@ async function withdrawFunds(input) {
225334
225403
  functionName: "transfer",
225335
225404
  args: [bridgeEvm, amountRaw]
225336
225405
  });
225337
- let txHash;
225338
- if (getSigType() === 3) {
225339
- const res = await sendWalletBatch(
225340
- [{ target: PUSD_COLLATERAL, value: "0", data }],
225341
- owner,
225342
- "Withdraw"
225343
- );
225344
- txHash = res.transactionHash;
225345
- } else {
225346
- const account = getPolymarketAccount();
225347
- const wallet = createWalletClient({
225348
- account,
225349
- chain: polygon,
225350
- transport: http(POLYGON_RPC_URLS[0])
225351
- });
225352
- txHash = await wallet.sendTransaction({
225353
- to: PUSD_COLLATERAL,
225354
- data,
225355
- chain: polygon,
225356
- account
225357
- });
225358
- await getPublicClient().waitForTransactionReceipt({ hash: txHash });
225359
- }
225406
+ const eoa = getSigType() !== 3;
225407
+ const txHash = await signUnderSpendPolicy(
225408
+ deps,
225409
+ {
225410
+ payTo: recipient,
225411
+ network: `eip155:${BASE_CHAIN_ID}`,
225412
+ asset: BASE_USDC,
225413
+ amount: amountRaw.toString()
225414
+ },
225415
+ "polymarket withdraw",
225416
+ async () => {
225417
+ if (!eoa) {
225418
+ const res = await sendWalletBatch(
225419
+ [{ target: PUSD_COLLATERAL, value: "0", data }],
225420
+ owner,
225421
+ "Withdraw"
225422
+ );
225423
+ return res.transactionHash;
225424
+ }
225425
+ const account = getPolymarketAccount();
225426
+ const wallet = createWalletClient({
225427
+ account,
225428
+ chain: polygon,
225429
+ transport: http(POLYGON_RPC_URLS[0])
225430
+ });
225431
+ return wallet.sendTransaction({
225432
+ to: PUSD_COLLATERAL,
225433
+ data,
225434
+ chain: polygon,
225435
+ account
225436
+ });
225437
+ }
225438
+ );
225439
+ if (eoa) await getPublicClient().waitForTransactionReceipt({ hash: txHash });
225360
225440
  return {
225361
225441
  text: [
225362
225442
  `\u2705 Withdrawal submitted: $${amountUsd.toFixed(2)} pUSD \u2192 USDC on Base`,
@@ -225391,6 +225471,7 @@ var init_withdraw = __esm({
225391
225471
  init_positions();
225392
225472
  init_relayer();
225393
225473
  init_setup();
225474
+ init_spend_policy();
225394
225475
  }
225395
225476
  });
225396
225477
 
@@ -226036,7 +226117,7 @@ async function bridgeAddressFor(vault) {
226036
226117
  throw new Error(`Bridge did not return a deposit address (got: ${JSON.stringify(res.data)}).`);
226037
226118
  return evm;
226038
226119
  }
226039
- async function fundVault(input) {
226120
+ async function fundVault(input, deps) {
226040
226121
  if (input.amount_usd === void 0 || input.amount_usd <= 0) {
226041
226122
  return {
226042
226123
  text: `Pass amount_usd \u2014 the USDC amount to move from your Base wallet into your Polymarket vault (e.g. amount_usd:5).`,
@@ -226093,12 +226174,12 @@ async function fundVault(input) {
226093
226174
  }
226094
226175
  const privateKey = getOrCreateWalletKey();
226095
226176
  const amountMicro = String(Math.floor(amountUsd * 10 ** USDC_DECIMALS));
226096
- const depositAuthorization = await createPaymentPayload(
226097
- privateKey,
226098
- agent,
226099
- bridge,
226100
- amountMicro,
226101
- `eip155:${BASE_CHAIN_ID}`
226177
+ const network = `eip155:${BASE_CHAIN_ID}`;
226178
+ const depositAuthorization = await signUnderSpendPolicy(
226179
+ deps,
226180
+ { payTo: bridge, network, asset: BASE_USDC, amount: amountMicro },
226181
+ "polymarket fund",
226182
+ () => createPaymentPayload(privateKey, agent, bridge, amountMicro, network)
226102
226183
  );
226103
226184
  const client = new BlockrunClient({ privateKey });
226104
226185
  const result = await client.post("/v1/polymarket/fund", {
@@ -226148,6 +226229,7 @@ var init_fund = __esm({
226148
226229
  init_constants3();
226149
226230
  init_positions();
226150
226231
  init_setup();
226232
+ init_spend_policy();
226151
226233
  FUND_FEE_USD = 0.01;
226152
226234
  USDC_DECIMALS = 6;
226153
226235
  FUND_MIN_USD = Number(process.env.POLYMARKET_FUND_MIN_USD || "2");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blockrun/clawrouter",
3
- "version": "0.12.263",
3
+ "version": "0.12.264",
4
4
  "description": "Smart LLM router \u2014 save 84% on inference costs. 76 models (7 free), one wallet, x402 micropayments.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",