logiqical 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -33,6 +33,7 @@ __export(index_exports, {
33
33
  AgentWallet: () => AgentWallet,
34
34
  BridgeModule: () => BridgeModule,
35
35
  CHAINS: () => CHAINS,
36
+ CopyTradingModule: () => CopyTradingModule,
36
37
  DefiModule: () => DefiModule,
37
38
  DexModule: () => DexModule,
38
39
  LaunchpadModule: () => LaunchpadModule,
@@ -52,7 +53,7 @@ __export(index_exports, {
52
53
  module.exports = __toCommonJS(index_exports);
53
54
 
54
55
  // src/client.ts
55
- var import_ethers9 = require("ethers");
56
+ var import_ethers10 = require("ethers");
56
57
 
57
58
  // src/wallet.ts
58
59
  var import_ethers = require("ethers");
@@ -490,6 +491,10 @@ var FRACTION_SCALER = 100;
490
491
  var ARENA_SOCIAL_API = "https://api.starsarena.com";
491
492
  var LIFI_API = "https://li.quest/v1";
492
493
  var HL_INFO = "https://api.hyperliquid.xyz/info";
494
+ var HL_DEPOSIT_ADDRESS = "0x2Df1c51E09aECF9cacB7bc98cB1742757f163dF7";
495
+ var USDC_ARBITRUM = "0xaf88d065e77c8cC2239327C5EDb3A432268e5831";
496
+ var ARBITRUM_CHAIN_ID = 42161;
497
+ var ARBITRUM_RPC = "https://arb1.arbitrum.io/rpc";
493
498
  var DEFAULT_SLIPPAGE_BPS = 500;
494
499
  var ERC20_ABI = [
495
500
  "function balanceOf(address owner) view returns (uint256)",
@@ -1186,6 +1191,7 @@ var DexModule = class {
1186
1191
  };
1187
1192
 
1188
1193
  // src/modules/perps.ts
1194
+ var import_ethers7 = require("ethers");
1189
1195
  var PerpsModule = class {
1190
1196
  constructor(arenaApiKey) {
1191
1197
  this.arenaApiKey = arenaApiKey;
@@ -1279,6 +1285,51 @@ var PerpsModule = class {
1279
1285
  async getOpenOrders(wallet) {
1280
1286
  return this.hlPost({ type: "openOrders", user: wallet });
1281
1287
  }
1288
+ // ── USDC Deposit to Hyperliquid (on Arbitrum) ──
1289
+ /** Check USDC balance on Arbitrum */
1290
+ async getArbitrumUSDCBalance(wallet) {
1291
+ const provider = new import_ethers7.JsonRpcProvider(ARBITRUM_RPC, ARBITRUM_CHAIN_ID);
1292
+ const usdc = new import_ethers7.Contract(USDC_ARBITRUM, ERC20_ABI, provider);
1293
+ const balance = await usdc.balanceOf(wallet);
1294
+ return import_ethers7.ethers.formatUnits(balance, 6);
1295
+ }
1296
+ /** Check ETH balance on Arbitrum (needed for gas) */
1297
+ async getArbitrumETHBalance(wallet) {
1298
+ const provider = new import_ethers7.JsonRpcProvider(ARBITRUM_RPC, ARBITRUM_CHAIN_ID);
1299
+ const balance = await provider.getBalance(wallet);
1300
+ return import_ethers7.ethers.formatEther(balance);
1301
+ }
1302
+ /**
1303
+ * Build a USDC deposit transaction for Hyperliquid on Arbitrum.
1304
+ * Returns an unsigned tx — use with agent.execute() after switching to Arbitrum network.
1305
+ *
1306
+ * Flow: agent.switchNetwork("arbitrum") → agent.execute(agent.perps.buildDepositUSDC(...))
1307
+ */
1308
+ buildDepositUSDC(amount) {
1309
+ const iface = new import_ethers7.ethers.Interface(["function transfer(address to, uint256 amount) returns (bool)"]);
1310
+ const amountWei = import_ethers7.ethers.parseUnits(amount, 6);
1311
+ const data = iface.encodeFunctionData("transfer", [HL_DEPOSIT_ADDRESS, amountWei]);
1312
+ return {
1313
+ transaction: {
1314
+ to: USDC_ARBITRUM,
1315
+ data,
1316
+ value: "0",
1317
+ chainId: ARBITRUM_CHAIN_ID,
1318
+ description: `Deposit ${amount} USDC to Hyperliquid`
1319
+ }
1320
+ };
1321
+ }
1322
+ /** Get deposit info (addresses + chain details) */
1323
+ getDepositInfo() {
1324
+ return {
1325
+ chain: "Arbitrum One",
1326
+ chainId: ARBITRUM_CHAIN_ID,
1327
+ usdcAddress: USDC_ARBITRUM,
1328
+ depositAddress: HL_DEPOSIT_ADDRESS,
1329
+ decimals: 6,
1330
+ tip: "Bridge USDC to Arbitrum first (use bridge module), then deposit to Hyperliquid"
1331
+ };
1332
+ }
1282
1333
  };
1283
1334
 
1284
1335
  // src/modules/bridge.ts
@@ -1435,37 +1486,37 @@ var BridgeModule = class {
1435
1486
  };
1436
1487
 
1437
1488
  // src/modules/tickets.ts
1438
- var import_ethers7 = require("ethers");
1489
+ var import_ethers8 = require("ethers");
1439
1490
  var TicketsModule = class {
1440
1491
  constructor(provider) {
1441
1492
  this.provider = provider;
1442
- this.contract = new import_ethers7.ethers.Contract(import_ethers7.ethers.getAddress(ARENA_SHARES_CONTRACT), SHARES_ABI, provider);
1493
+ this.contract = new import_ethers8.ethers.Contract(import_ethers8.ethers.getAddress(ARENA_SHARES_CONTRACT), SHARES_ABI, provider);
1443
1494
  }
1444
1495
  contract;
1445
1496
  async getBuyPrice(subject, amount = "1") {
1446
1497
  const fractionalAmount = this.ticketsToFractional(amount);
1447
- const subjectAddr = import_ethers7.ethers.getAddress(subject);
1498
+ const subjectAddr = import_ethers8.ethers.getAddress(subject);
1448
1499
  const [price, priceWithFee] = await Promise.all([
1449
1500
  this.contract.getBuyPriceForFractionalShares(subjectAddr, fractionalAmount),
1450
1501
  this.contract.getBuyPriceForFractionalSharesAfterFee(subjectAddr, fractionalAmount)
1451
1502
  ]);
1452
- return { price: import_ethers7.ethers.formatEther(price), priceWithFee: import_ethers7.ethers.formatEther(priceWithFee), tickets: amount, fractionalAmount };
1503
+ return { price: import_ethers8.ethers.formatEther(price), priceWithFee: import_ethers8.ethers.formatEther(priceWithFee), tickets: amount, fractionalAmount };
1453
1504
  }
1454
1505
  async getSellPrice(subject, amount = "1") {
1455
1506
  const fractionalAmount = this.ticketsToFractional(amount);
1456
- const subjectAddr = import_ethers7.ethers.getAddress(subject);
1507
+ const subjectAddr = import_ethers8.ethers.getAddress(subject);
1457
1508
  const [price, priceAfterFee] = await Promise.all([
1458
1509
  this.contract.getSellPriceForFractionalShares(subjectAddr, fractionalAmount),
1459
1510
  this.contract.getSellPriceForFractionalSharesAfterFee(subjectAddr, fractionalAmount)
1460
1511
  ]);
1461
- return { price: import_ethers7.ethers.formatEther(price), priceAfterFee: import_ethers7.ethers.formatEther(priceAfterFee), tickets: amount, fractionalAmount };
1512
+ return { price: import_ethers8.ethers.formatEther(price), priceAfterFee: import_ethers8.ethers.formatEther(priceAfterFee), tickets: amount, fractionalAmount };
1462
1513
  }
1463
1514
  async getBalance(subject, user) {
1464
- const frac = await this.contract.getMyFractionalShares(import_ethers7.ethers.getAddress(subject), import_ethers7.ethers.getAddress(user));
1515
+ const frac = await this.contract.getMyFractionalShares(import_ethers8.ethers.getAddress(subject), import_ethers8.ethers.getAddress(user));
1465
1516
  return { tickets: (Number(frac) / FRACTION_SCALER).toString(), fractionalAmount: frac.toString() };
1466
1517
  }
1467
1518
  async getSupply(subject) {
1468
- const subjectAddr = import_ethers7.ethers.getAddress(subject);
1519
+ const subjectAddr = import_ethers8.ethers.getAddress(subject);
1469
1520
  const [wholeSupply, fracSupply] = await Promise.all([
1470
1521
  this.contract.getSharesSupply(subjectAddr),
1471
1522
  this.contract.getTotalFractionalSupply(subjectAddr)
@@ -1483,42 +1534,42 @@ var TicketsModule = class {
1483
1534
  }
1484
1535
  async buildBuyTx(wallet, subject, amount = "1") {
1485
1536
  const fractionalAmount = this.ticketsToFractional(amount);
1486
- const subjectAddr = import_ethers7.ethers.getAddress(subject);
1487
- const userAddr = import_ethers7.ethers.getAddress(wallet);
1537
+ const subjectAddr = import_ethers8.ethers.getAddress(subject);
1538
+ const userAddr = import_ethers8.ethers.getAddress(wallet);
1488
1539
  const cost = await this.contract.getBuyPriceForFractionalSharesAfterFee(subjectAddr, fractionalAmount);
1489
1540
  if (cost === 0n) throw new Error("Could not get buy price \u2014 subject may not exist");
1490
- const iface = new import_ethers7.ethers.Interface(SHARES_ABI);
1541
+ const iface = new import_ethers8.ethers.Interface(SHARES_ABI);
1491
1542
  const data = iface.encodeFunctionData("buyFractionalShares", [subjectAddr, userAddr, fractionalAmount]);
1492
1543
  return {
1493
1544
  transaction: {
1494
- to: import_ethers7.ethers.getAddress(ARENA_SHARES_CONTRACT),
1545
+ to: import_ethers8.ethers.getAddress(ARENA_SHARES_CONTRACT),
1495
1546
  data,
1496
- value: import_ethers7.ethers.toBeHex(cost, 32),
1547
+ value: import_ethers8.ethers.toBeHex(cost, 32),
1497
1548
  chainId: CHAIN_ID,
1498
1549
  gasLimit: "200000",
1499
- description: `Buy ${amount} ticket(s) for ~${import_ethers7.ethers.formatEther(cost)} AVAX`
1550
+ description: `Buy ${amount} ticket(s) for ~${import_ethers8.ethers.formatEther(cost)} AVAX`
1500
1551
  }
1501
1552
  };
1502
1553
  }
1503
1554
  async buildSellTx(wallet, subject, amount = "1") {
1504
1555
  const fractionalAmount = this.ticketsToFractional(amount);
1505
- const subjectAddr = import_ethers7.ethers.getAddress(subject);
1506
- const userAddr = import_ethers7.ethers.getAddress(wallet);
1556
+ const subjectAddr = import_ethers8.ethers.getAddress(subject);
1557
+ const userAddr = import_ethers8.ethers.getAddress(wallet);
1507
1558
  const balance = await this.contract.getMyFractionalShares(subjectAddr, userAddr);
1508
1559
  if (balance < BigInt(fractionalAmount)) {
1509
1560
  throw new Error(`Insufficient tickets: have ${Number(balance) / FRACTION_SCALER}, trying to sell ${amount}`);
1510
1561
  }
1511
1562
  const proceeds = await this.contract.getSellPriceForFractionalSharesAfterFee(subjectAddr, fractionalAmount);
1512
- const iface = new import_ethers7.ethers.Interface(SHARES_ABI);
1563
+ const iface = new import_ethers8.ethers.Interface(SHARES_ABI);
1513
1564
  const data = iface.encodeFunctionData("sellFractionalShares", [subjectAddr, userAddr, fractionalAmount]);
1514
1565
  return {
1515
1566
  transaction: {
1516
- to: import_ethers7.ethers.getAddress(ARENA_SHARES_CONTRACT),
1567
+ to: import_ethers8.ethers.getAddress(ARENA_SHARES_CONTRACT),
1517
1568
  data,
1518
1569
  value: "0x0",
1519
1570
  chainId: CHAIN_ID,
1520
1571
  gasLimit: "200000",
1521
- description: `Sell ${amount} ticket(s) for ~${import_ethers7.ethers.formatEther(proceeds)} AVAX`
1572
+ description: `Sell ${amount} ticket(s) for ~${import_ethers8.ethers.formatEther(proceeds)} AVAX`
1522
1573
  }
1523
1574
  };
1524
1575
  }
@@ -1537,6 +1588,53 @@ var SocialModule = class {
1537
1588
  setArenaApiKey(key) {
1538
1589
  this.arenaApiKey = key;
1539
1590
  }
1591
+ // ── Agent Registration (no auth needed — returns API key) ──
1592
+ /**
1593
+ * Register a new AI agent on Arena. Returns API key (shown once — save immediately).
1594
+ * After registration, owner must claim by posting: "I'm claiming my AI Agent \"<name>\"\nVerification Code: <code>"
1595
+ */
1596
+ static async registerAgent(opts) {
1597
+ const res = await fetch(`${ARENA_SOCIAL_API}/agents/register`, {
1598
+ method: "POST",
1599
+ headers: { "Content-Type": "application/json" },
1600
+ body: JSON.stringify(opts)
1601
+ });
1602
+ const data = await res.json();
1603
+ if (!res.ok) throw new Error(data.message || data.error || `Registration failed (${res.status})`);
1604
+ return data;
1605
+ }
1606
+ // ── Feed Auto-Posting (trade updates) ──
1607
+ /** Post a formatted trade update to the Arena feed */
1608
+ async postTradeUpdate(trade) {
1609
+ const lines = [];
1610
+ const emoji = {
1611
+ buy: "\u{1F7E2}",
1612
+ sell: "\u{1F534}",
1613
+ swap: "\u{1F504}",
1614
+ bridge: "\u{1F309}",
1615
+ stake: "\u{1F512}",
1616
+ long: "\u{1F4C8}",
1617
+ short: "\u{1F4C9}",
1618
+ close: "\u2705"
1619
+ };
1620
+ const icon = emoji[trade.action] || "\u{1F4B0}";
1621
+ if (trade.action === "swap" && trade.fromToken && trade.toToken) {
1622
+ lines.push(`${icon} Swapped ${trade.amount || ""} ${trade.fromToken} \u2192 ${trade.toToken}`);
1623
+ } else if (trade.action === "bridge" && trade.fromToken) {
1624
+ lines.push(`${icon} Bridged ${trade.amount || ""} ${trade.fromToken}`);
1625
+ } else if (trade.action === "long" || trade.action === "short") {
1626
+ lines.push(`${icon} Opened ${trade.action.toUpperCase()} ${trade.token || ""} ${trade.amount ? `(${trade.amount})` : ""}`);
1627
+ } else if (trade.action === "close") {
1628
+ lines.push(`${icon} Closed ${trade.token || ""} position${trade.pnl ? ` | PnL: ${trade.pnl}` : ""}`);
1629
+ } else {
1630
+ lines.push(`${icon} ${trade.action.toUpperCase()} ${trade.amount || ""} ${trade.token || ""}`);
1631
+ }
1632
+ if (trade.price) lines.push(`Price: $${trade.price}`);
1633
+ if (trade.hash) lines.push(`tx: ${trade.hash}`);
1634
+ if (trade.extra) lines.push(trade.extra);
1635
+ const content = lines.join("<br>");
1636
+ return this.createThread(content);
1637
+ }
1540
1638
  async request(method, path, body, query) {
1541
1639
  if (!this.arenaApiKey) throw new Error("Arena API key required for social endpoints. Pass arenaApiKey in config.");
1542
1640
  let url = `${ARENA_SOCIAL_API}${path}`;
@@ -1990,7 +2088,7 @@ var MarketModule = class {
1990
2088
  };
1991
2089
 
1992
2090
  // src/modules/defi.ts
1993
- var import_ethers8 = require("ethers");
2091
+ var import_ethers9 = require("ethers");
1994
2092
  var SAVAX_ADDRESS = "0x2b2C81e08f1Af8835a78Bb2A90AE924ACE0eA4bE";
1995
2093
  var SAVAX_ABI = [
1996
2094
  "function submit() payable returns (uint256)",
@@ -2031,7 +2129,7 @@ var ERC20_ABI2 = [
2031
2129
  var DefiModule = class {
2032
2130
  constructor(provider) {
2033
2131
  this.provider = provider;
2034
- this.savax = new import_ethers8.ethers.Contract(import_ethers8.ethers.getAddress(SAVAX_ADDRESS), SAVAX_ABI, provider);
2132
+ this.savax = new import_ethers9.ethers.Contract(import_ethers9.ethers.getAddress(SAVAX_ADDRESS), SAVAX_ABI, provider);
2035
2133
  }
2036
2134
  savax;
2037
2135
  // ── sAVAX Liquid Staking ──
@@ -2041,36 +2139,36 @@ var DefiModule = class {
2041
2139
  this.savax.totalPooledAvax(),
2042
2140
  this.savax.totalShares()
2043
2141
  ]);
2044
- const exchangeRate = totalShares > 0n ? import_ethers8.ethers.formatEther(totalPooled * import_ethers8.ethers.parseEther("1") / totalShares) : "1.0";
2142
+ const exchangeRate = totalShares > 0n ? import_ethers9.ethers.formatEther(totalPooled * import_ethers9.ethers.parseEther("1") / totalShares) : "1.0";
2045
2143
  const result = {
2046
2144
  exchangeRate,
2047
- totalPooledAvax: import_ethers8.ethers.formatEther(totalPooled),
2048
- totalShares: import_ethers8.ethers.formatEther(totalShares)
2145
+ totalPooledAvax: import_ethers9.ethers.formatEther(totalPooled),
2146
+ totalShares: import_ethers9.ethers.formatEther(totalShares)
2049
2147
  };
2050
2148
  if (wallet) {
2051
2149
  const balance = await this.savax.balanceOf(wallet);
2052
2150
  const avaxValue = await this.savax.getPooledAvaxByShares(balance);
2053
- result.balance = import_ethers8.ethers.formatEther(balance);
2054
- result.balanceInAvax = import_ethers8.ethers.formatEther(avaxValue);
2151
+ result.balance = import_ethers9.ethers.formatEther(balance);
2152
+ result.balanceInAvax = import_ethers9.ethers.formatEther(avaxValue);
2055
2153
  }
2056
2154
  return result;
2057
2155
  }
2058
2156
  /** Quote: how much sAVAX for staking AVAX */
2059
2157
  async sAvaxStakeQuote(avaxAmount) {
2060
- const avaxWei = import_ethers8.ethers.parseEther(avaxAmount);
2158
+ const avaxWei = import_ethers9.ethers.parseEther(avaxAmount);
2061
2159
  const shares = await this.savax.getSharesByPooledAvax(avaxWei);
2062
- return { avaxIn: avaxAmount, savaxOut: import_ethers8.ethers.formatEther(shares) };
2160
+ return { avaxIn: avaxAmount, savaxOut: import_ethers9.ethers.formatEther(shares) };
2063
2161
  }
2064
2162
  /** Build tx to stake AVAX → sAVAX */
2065
2163
  async buildSAvaxStake(avaxAmount) {
2066
- const avaxWei = import_ethers8.ethers.parseEther(avaxAmount);
2067
- const iface = new import_ethers8.ethers.Interface(SAVAX_ABI);
2164
+ const avaxWei = import_ethers9.ethers.parseEther(avaxAmount);
2165
+ const iface = new import_ethers9.ethers.Interface(SAVAX_ABI);
2068
2166
  const data = iface.encodeFunctionData("submit", []);
2069
2167
  return {
2070
2168
  transactions: [{
2071
- to: import_ethers8.ethers.getAddress(SAVAX_ADDRESS),
2169
+ to: import_ethers9.ethers.getAddress(SAVAX_ADDRESS),
2072
2170
  data,
2073
- value: import_ethers8.ethers.toBeHex(avaxWei, 32),
2171
+ value: import_ethers9.ethers.toBeHex(avaxWei, 32),
2074
2172
  chainId: CHAIN_ID,
2075
2173
  gasLimit: "300000",
2076
2174
  description: `Stake ${avaxAmount} AVAX \u2192 sAVAX`
@@ -2083,26 +2181,26 @@ var DefiModule = class {
2083
2181
  if (amount === "max") {
2084
2182
  shareAmount = await this.savax.balanceOf(wallet);
2085
2183
  } else {
2086
- shareAmount = import_ethers8.ethers.parseEther(amount);
2184
+ shareAmount = import_ethers9.ethers.parseEther(amount);
2087
2185
  }
2088
2186
  if (shareAmount === 0n) throw new Error("Zero sAVAX balance");
2089
- const iface = new import_ethers8.ethers.Interface(SAVAX_ABI);
2187
+ const iface = new import_ethers9.ethers.Interface(SAVAX_ABI);
2090
2188
  const data = iface.encodeFunctionData("requestUnlock", [shareAmount]);
2091
2189
  return {
2092
2190
  transactions: [{
2093
- to: import_ethers8.ethers.getAddress(SAVAX_ADDRESS),
2191
+ to: import_ethers9.ethers.getAddress(SAVAX_ADDRESS),
2094
2192
  data,
2095
2193
  value: "0",
2096
2194
  chainId: CHAIN_ID,
2097
2195
  gasLimit: "300000",
2098
- description: `Request unstake ${import_ethers8.ethers.formatEther(shareAmount)} sAVAX`
2196
+ description: `Request unstake ${import_ethers9.ethers.formatEther(shareAmount)} sAVAX`
2099
2197
  }]
2100
2198
  };
2101
2199
  }
2102
2200
  // ── ERC-4626 Vaults ──
2103
2201
  /** Get info about any ERC-4626 vault */
2104
2202
  async vaultInfo(vaultAddress, wallet) {
2105
- const vault = new import_ethers8.ethers.Contract(import_ethers8.ethers.getAddress(vaultAddress), VAULT_ABI, this.provider);
2203
+ const vault = new import_ethers9.ethers.Contract(import_ethers9.ethers.getAddress(vaultAddress), VAULT_ABI, this.provider);
2106
2204
  const [name, symbol, asset, totalAssets, totalSupply, decimals] = await Promise.all([
2107
2205
  vault.name(),
2108
2206
  vault.symbol(),
@@ -2111,70 +2209,70 @@ var DefiModule = class {
2111
2209
  vault.totalSupply(),
2112
2210
  vault.decimals()
2113
2211
  ]);
2114
- const sharePrice = totalSupply > 0n ? import_ethers8.ethers.formatUnits(totalAssets * 10n ** BigInt(decimals) / totalSupply, decimals) : "1.0";
2212
+ const sharePrice = totalSupply > 0n ? import_ethers9.ethers.formatUnits(totalAssets * 10n ** BigInt(decimals) / totalSupply, decimals) : "1.0";
2115
2213
  const result = {
2116
2214
  name,
2117
2215
  symbol,
2118
2216
  asset,
2119
- totalAssets: import_ethers8.ethers.formatUnits(totalAssets, decimals),
2120
- totalSupply: import_ethers8.ethers.formatUnits(totalSupply, decimals),
2217
+ totalAssets: import_ethers9.ethers.formatUnits(totalAssets, decimals),
2218
+ totalSupply: import_ethers9.ethers.formatUnits(totalSupply, decimals),
2121
2219
  sharePrice
2122
2220
  };
2123
2221
  if (wallet) {
2124
2222
  const shares = await vault.balanceOf(wallet);
2125
2223
  const assets = shares > 0n ? await vault.convertToAssets(shares) : 0n;
2126
- result.userShares = import_ethers8.ethers.formatUnits(shares, decimals);
2127
- result.userAssets = import_ethers8.ethers.formatUnits(assets, decimals);
2224
+ result.userShares = import_ethers9.ethers.formatUnits(shares, decimals);
2225
+ result.userAssets = import_ethers9.ethers.formatUnits(assets, decimals);
2128
2226
  }
2129
2227
  return result;
2130
2228
  }
2131
2229
  /** Quote vault deposit — how many shares for given assets */
2132
2230
  async vaultDepositQuote(vaultAddress, amount) {
2133
- const vault = new import_ethers8.ethers.Contract(import_ethers8.ethers.getAddress(vaultAddress), VAULT_ABI, this.provider);
2231
+ const vault = new import_ethers9.ethers.Contract(import_ethers9.ethers.getAddress(vaultAddress), VAULT_ABI, this.provider);
2134
2232
  const decimals = Number(await vault.decimals());
2135
- const assetsWei = import_ethers8.ethers.parseUnits(amount, decimals);
2233
+ const assetsWei = import_ethers9.ethers.parseUnits(amount, decimals);
2136
2234
  const shares = await vault.previewDeposit(assetsWei);
2137
- return { assetsIn: amount, sharesOut: import_ethers8.ethers.formatUnits(shares, decimals) };
2235
+ return { assetsIn: amount, sharesOut: import_ethers9.ethers.formatUnits(shares, decimals) };
2138
2236
  }
2139
2237
  /** Build txs to deposit into an ERC-4626 vault: [approve, deposit] */
2140
2238
  async buildVaultDeposit(wallet, vaultAddress, amount) {
2141
- const vaultAddr = import_ethers8.ethers.getAddress(vaultAddress);
2142
- const vault = new import_ethers8.ethers.Contract(vaultAddr, VAULT_ABI, this.provider);
2239
+ const vaultAddr = import_ethers9.ethers.getAddress(vaultAddress);
2240
+ const vault = new import_ethers9.ethers.Contract(vaultAddr, VAULT_ABI, this.provider);
2143
2241
  const assetAddr = await vault.asset();
2144
- const assetToken = new import_ethers8.ethers.Contract(assetAddr, ERC20_ABI2, this.provider);
2242
+ const assetToken = new import_ethers9.ethers.Contract(assetAddr, ERC20_ABI2, this.provider);
2145
2243
  const decimals = Number(await assetToken.decimals());
2146
2244
  let depositAmount;
2147
2245
  if (amount === "max") {
2148
2246
  depositAmount = await assetToken.balanceOf(wallet);
2149
2247
  } else {
2150
- depositAmount = import_ethers8.ethers.parseUnits(amount, decimals);
2248
+ depositAmount = import_ethers9.ethers.parseUnits(amount, decimals);
2151
2249
  }
2152
2250
  if (depositAmount === 0n) throw new Error("Zero balance to deposit");
2153
- const erc20Iface = new import_ethers8.ethers.Interface(ERC20_ABI2);
2251
+ const erc20Iface = new import_ethers9.ethers.Interface(ERC20_ABI2);
2154
2252
  const approveData = erc20Iface.encodeFunctionData("approve", [vaultAddr, depositAmount]);
2155
- const vaultIface = new import_ethers8.ethers.Interface(VAULT_ABI);
2253
+ const vaultIface = new import_ethers9.ethers.Interface(VAULT_ABI);
2156
2254
  const depositData = vaultIface.encodeFunctionData("deposit", [depositAmount, wallet]);
2157
2255
  return {
2158
2256
  transactions: [
2159
2257
  { to: assetAddr, data: approveData, value: "0", chainId: CHAIN_ID, gasLimit: "60000", description: `Approve asset for vault deposit` },
2160
- { to: vaultAddr, data: depositData, value: "0", chainId: CHAIN_ID, gasLimit: "300000", description: `Deposit ${import_ethers8.ethers.formatUnits(depositAmount, decimals)} into vault` }
2258
+ { to: vaultAddr, data: depositData, value: "0", chainId: CHAIN_ID, gasLimit: "300000", description: `Deposit ${import_ethers9.ethers.formatUnits(depositAmount, decimals)} into vault` }
2161
2259
  ]
2162
2260
  };
2163
2261
  }
2164
2262
  /** Build tx to withdraw from an ERC-4626 vault */
2165
2263
  async buildVaultWithdraw(wallet, vaultAddress, amount) {
2166
- const vaultAddr = import_ethers8.ethers.getAddress(vaultAddress);
2167
- const vault = new import_ethers8.ethers.Contract(vaultAddr, VAULT_ABI, this.provider);
2264
+ const vaultAddr = import_ethers9.ethers.getAddress(vaultAddress);
2265
+ const vault = new import_ethers9.ethers.Contract(vaultAddr, VAULT_ABI, this.provider);
2168
2266
  const decimals = Number(await vault.decimals());
2169
2267
  let withdrawAmount;
2170
2268
  if (amount === "max") {
2171
2269
  const shares = await vault.balanceOf(wallet);
2172
2270
  withdrawAmount = await vault.convertToAssets(shares);
2173
2271
  } else {
2174
- withdrawAmount = import_ethers8.ethers.parseUnits(amount, decimals);
2272
+ withdrawAmount = import_ethers9.ethers.parseUnits(amount, decimals);
2175
2273
  }
2176
2274
  if (withdrawAmount === 0n) throw new Error("Nothing to withdraw");
2177
- const iface = new import_ethers8.ethers.Interface(VAULT_ABI);
2275
+ const iface = new import_ethers9.ethers.Interface(VAULT_ABI);
2178
2276
  const data = iface.encodeFunctionData("withdraw", [withdrawAmount, wallet, wallet]);
2179
2277
  return {
2180
2278
  transactions: [{
@@ -2183,12 +2281,139 @@ var DefiModule = class {
2183
2281
  value: "0",
2184
2282
  chainId: CHAIN_ID,
2185
2283
  gasLimit: "300000",
2186
- description: `Withdraw ${import_ethers8.ethers.formatUnits(withdrawAmount, decimals)} from vault`
2284
+ description: `Withdraw ${import_ethers9.ethers.formatUnits(withdrawAmount, decimals)} from vault`
2187
2285
  }]
2188
2286
  };
2189
2287
  }
2190
2288
  };
2191
2289
 
2290
+ // src/modules/copytrading.ts
2291
+ var CopyTradingModule = class {
2292
+ perps;
2293
+ constructor(perps) {
2294
+ this.perps = perps;
2295
+ }
2296
+ /** Fetch all open positions for a Hyperliquid wallet */
2297
+ async getTargetPositions(targetWallet) {
2298
+ const state = await this.perps.getPositions(targetWallet);
2299
+ const assetPositions = state?.assetPositions ?? [];
2300
+ return assetPositions.map((ap) => ap.position).filter((p) => p && parseFloat(p.szi) !== 0);
2301
+ }
2302
+ /** Fetch your agent's current positions */
2303
+ async getAgentPositions(agentWallet) {
2304
+ const state = await this.perps.getPositions(agentWallet);
2305
+ const assetPositions = state?.assetPositions ?? [];
2306
+ return assetPositions.map((ap) => ap.position).filter((p) => p && parseFloat(p.szi) !== 0);
2307
+ }
2308
+ /**
2309
+ * Compare target wallet positions with agent positions and return orders needed to mirror.
2310
+ * Uses proportional sizing based on the scale factor.
2311
+ *
2312
+ * @param targetWallet - Wallet to copy from
2313
+ * @param agentWallet - Your agent's wallet
2314
+ * @param scaleFactor - Position scale (0.1 = 10% of target size, 1.0 = same size)
2315
+ */
2316
+ async calculateMirrorOrders(targetWallet, agentWallet, scaleFactor = 0.1) {
2317
+ const [targetPositions, agentPositions] = await Promise.all([
2318
+ this.getTargetPositions(targetWallet),
2319
+ this.getAgentPositions(agentWallet)
2320
+ ]);
2321
+ const agentMap = /* @__PURE__ */ new Map();
2322
+ for (const p of agentPositions) {
2323
+ agentMap.set(p.coin, p);
2324
+ }
2325
+ const targetMap = /* @__PURE__ */ new Map();
2326
+ for (const p of targetPositions) {
2327
+ targetMap.set(p.coin, p);
2328
+ }
2329
+ const orders = [];
2330
+ for (const [coin, targetPos] of targetMap) {
2331
+ const targetSize = parseFloat(targetPos.szi);
2332
+ const direction = targetSize > 0 ? "long" : "short";
2333
+ const desiredSize = Math.abs(targetSize) * scaleFactor;
2334
+ const agentPos = agentMap.get(coin);
2335
+ if (!agentPos) {
2336
+ orders.push({ symbol: coin, direction, size: desiredSize, action: "open", reason: `Mirror ${coin} ${direction} from target` });
2337
+ } else {
2338
+ const agentSize = parseFloat(agentPos.szi);
2339
+ const agentDir = agentSize > 0 ? "long" : "short";
2340
+ if (agentDir !== direction) {
2341
+ orders.push({ symbol: coin, direction: agentDir, size: Math.abs(agentSize), action: "close", reason: `Close ${agentDir} to flip to ${direction}` });
2342
+ orders.push({ symbol: coin, direction, size: desiredSize, action: "open", reason: `Mirror ${coin} ${direction} from target` });
2343
+ }
2344
+ }
2345
+ }
2346
+ for (const [coin, agentPos] of agentMap) {
2347
+ if (!targetMap.has(coin)) {
2348
+ const agentSize = parseFloat(agentPos.szi);
2349
+ const dir = agentSize > 0 ? "long" : "short";
2350
+ orders.push({ symbol: coin, direction: dir, size: Math.abs(agentSize), action: "close", reason: `Target closed ${coin} position` });
2351
+ }
2352
+ }
2353
+ return { orders, targetPositions, agentPositions };
2354
+ }
2355
+ /**
2356
+ * Execute mirror orders via the perps module (Arena API).
2357
+ * Returns results for each order.
2358
+ */
2359
+ async executeMirrorOrders(orders, currentPrices) {
2360
+ const results = [];
2361
+ for (const order of orders) {
2362
+ const price = currentPrices[order.symbol];
2363
+ if (!price) {
2364
+ results.push({ order, error: `No price for ${order.symbol}` });
2365
+ continue;
2366
+ }
2367
+ try {
2368
+ if (order.action === "close") {
2369
+ const result = await this.perps.closePosition(order.symbol, order.direction, order.size, price);
2370
+ results.push({ order, result });
2371
+ } else {
2372
+ const result = await this.perps.placeOrder([{
2373
+ symbol: order.symbol,
2374
+ direction: order.direction,
2375
+ orderType: "market",
2376
+ leverageType: "cross",
2377
+ size: order.size,
2378
+ leverage: 1
2379
+ }]);
2380
+ results.push({ order, result });
2381
+ }
2382
+ } catch (e) {
2383
+ results.push({ order, error: e.message });
2384
+ }
2385
+ }
2386
+ return results;
2387
+ }
2388
+ /**
2389
+ * One-shot copy: calculate + execute mirror orders in one call.
2390
+ * Fetches current prices from Hyperliquid for execution.
2391
+ */
2392
+ async copyOnce(targetWallet, agentWallet, scaleFactor = 0.1) {
2393
+ const { orders } = await this.calculateMirrorOrders(targetWallet, agentWallet, scaleFactor);
2394
+ if (orders.length === 0) return { orders, results: [] };
2395
+ const pairs = await this.perps.getTradingPairs();
2396
+ const midPrices = await this.fetchMidPrices(orders.map((o) => o.symbol), pairs.pairs);
2397
+ const results = await this.executeMirrorOrders(orders, midPrices);
2398
+ return { orders, results };
2399
+ }
2400
+ /** Fetch mid-market prices from Hyperliquid for given symbols */
2401
+ async fetchMidPrices(symbols, pairs) {
2402
+ const res = await fetch(HL_INFO, {
2403
+ method: "POST",
2404
+ headers: { "Content-Type": "application/json" },
2405
+ body: JSON.stringify({ type: "allMids" })
2406
+ });
2407
+ if (!res.ok) throw new Error(`Failed to fetch mid prices: ${res.status}`);
2408
+ const mids = await res.json();
2409
+ const prices = {};
2410
+ for (const sym of symbols) {
2411
+ if (mids[sym]) prices[sym] = parseFloat(mids[sym]);
2412
+ }
2413
+ return prices;
2414
+ }
2415
+ };
2416
+
2192
2417
  // src/client.ts
2193
2418
  var Logiqical = class _Logiqical {
2194
2419
  /** Buy/sell ARENA tokens via LFJ DEX */
@@ -2213,6 +2438,8 @@ var Logiqical = class _Logiqical {
2213
2438
  market;
2214
2439
  /** DeFi — sAVAX liquid staking + ERC-4626 vaults */
2215
2440
  defi;
2441
+ /** Copy trading — mirror Hyperliquid wallet positions */
2442
+ copyTrading;
2216
2443
  /** The agent's wallet address */
2217
2444
  address;
2218
2445
  /** The local wallet (null if read-only mode) */
@@ -2233,7 +2460,7 @@ var Logiqical = class _Logiqical {
2233
2460
  this.provider = this.agentWallet.provider;
2234
2461
  this.address = this.agentWallet.address;
2235
2462
  } else if (config.mnemonic) {
2236
- const hdWallet = import_ethers9.ethers.HDNodeWallet.fromPhrase(config.mnemonic);
2463
+ const hdWallet = import_ethers10.ethers.HDNodeWallet.fromPhrase(config.mnemonic);
2237
2464
  this.agentWallet = AgentWallet.fromPrivateKey(hdWallet.privateKey, {
2238
2465
  network: config.network,
2239
2466
  rpcUrl: config.rpcUrl
@@ -2259,6 +2486,7 @@ var Logiqical = class _Logiqical {
2259
2486
  this.signals = new SignalsModule();
2260
2487
  this.market = new MarketModule();
2261
2488
  this.defi = new DefiModule(this.provider);
2489
+ this.copyTrading = new CopyTradingModule(this.perps);
2262
2490
  }
2263
2491
  // ── Factory Methods ──
2264
2492
  /** Generate a brand new agent wallet */
@@ -2334,9 +2562,9 @@ var Logiqical = class _Logiqical {
2334
2562
  */
2335
2563
  async call(intent) {
2336
2564
  this.requireWallet("call");
2337
- const iface = new import_ethers9.ethers.Interface(intent.abi);
2565
+ const iface = new import_ethers10.ethers.Interface(intent.abi);
2338
2566
  const data = iface.encodeFunctionData(intent.method, intent.args ?? []);
2339
- const valueWei = intent.value ? import_ethers9.ethers.parseEther(intent.value).toString() : "0";
2567
+ const valueWei = intent.value ? import_ethers10.ethers.parseEther(intent.value).toString() : "0";
2340
2568
  const policyTx = { to: intent.contract, data, value: valueWei, chainId: 43114 };
2341
2569
  this.policyEngine.check(policyTx);
2342
2570
  if (this.policyEngine.shouldSimulate) {
@@ -2345,22 +2573,22 @@ var Logiqical = class _Logiqical {
2345
2573
  if (this.policyEngine.isDryRun) {
2346
2574
  return { hash: "0x_dry_run", receipt: { status: 1, blockNumber: 0, gasUsed: "0", transactionHash: "0x_dry_run" } };
2347
2575
  }
2348
- const contract = new import_ethers9.Contract(
2349
- import_ethers9.ethers.getAddress(intent.contract),
2576
+ const contract = new import_ethers10.Contract(
2577
+ import_ethers10.ethers.getAddress(intent.contract),
2350
2578
  intent.abi,
2351
2579
  this.agentWallet.wallet
2352
2580
  );
2353
2581
  const tx = await contract[intent.method](
2354
2582
  ...intent.args ?? [],
2355
2583
  {
2356
- value: intent.value ? import_ethers9.ethers.parseEther(intent.value) : void 0,
2584
+ value: intent.value ? import_ethers10.ethers.parseEther(intent.value) : void 0,
2357
2585
  gasLimit: intent.gasLimit ?? void 0
2358
2586
  }
2359
2587
  );
2360
2588
  const receipt = await tx.wait(1);
2361
2589
  if (!receipt) throw new Error(`Transaction ${tx.hash} failed \u2014 no receipt.`);
2362
2590
  if (intent.value) {
2363
- this.policyEngine.recordSpend(import_ethers9.ethers.parseEther(intent.value));
2591
+ this.policyEngine.recordSpend(import_ethers10.ethers.parseEther(intent.value));
2364
2592
  }
2365
2593
  return {
2366
2594
  hash: tx.hash,
@@ -2375,7 +2603,7 @@ var Logiqical = class _Logiqical {
2375
2603
  /** Send native token (AVAX) — policy check + simulate + sign + broadcast */
2376
2604
  async send(to, amount) {
2377
2605
  this.requireWallet("send");
2378
- const valueWei = import_ethers9.ethers.parseEther(amount);
2606
+ const valueWei = import_ethers10.ethers.parseEther(amount);
2379
2607
  const policyTx = { to, data: "0x", value: valueWei.toString(), chainId: 43114 };
2380
2608
  this.policyEngine.check(policyTx);
2381
2609
  if (this.policyEngine.isDryRun) {
@@ -2442,7 +2670,7 @@ var Logiqical = class _Logiqical {
2442
2670
  async getBalance() {
2443
2671
  if (this.agentWallet) return this.agentWallet.getBalance();
2444
2672
  const balance = await this.provider.getBalance(this.address);
2445
- return import_ethers9.ethers.formatEther(balance);
2673
+ return import_ethers10.ethers.formatEther(balance);
2446
2674
  }
2447
2675
  /** Sign a message */
2448
2676
  async signMessage(message) {
@@ -2493,7 +2721,7 @@ var Logiqical = class _Logiqical {
2493
2721
  }
2494
2722
  const rpcUrl = config.rpcUrl ?? chain.rpcUrl;
2495
2723
  const chainId = chain?.chainId ?? void 0;
2496
- return { provider: new import_ethers9.JsonRpcProvider(rpcUrl, chainId) };
2724
+ return { provider: new import_ethers10.JsonRpcProvider(rpcUrl, chainId) };
2497
2725
  }
2498
2726
  };
2499
2727
  var LogiqicalClient = Logiqical;
@@ -2517,6 +2745,7 @@ var LogiqicalError = class _LogiqicalError extends Error {
2517
2745
  AgentWallet,
2518
2746
  BridgeModule,
2519
2747
  CHAINS,
2748
+ CopyTradingModule,
2520
2749
  DefiModule,
2521
2750
  DexModule,
2522
2751
  LaunchpadModule,