@owney/sdk 0.7.22-beta.3 → 0.7.22-beta.5

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.
@@ -138,7 +138,7 @@ var VaultNotSponsorableError = class extends Error {
138
138
  }
139
139
  };
140
140
  async function resolveVault(ctx) {
141
- const registered = await ctx.api.getVault(ctx.wallet.ownerAddress);
141
+ const registered = await ctx.api.getVault(ctx.wallet.smartAccountAddress);
142
142
  const smartAccount = ctx.wallet.smartAccountAddress;
143
143
  if (!registered.userVaultAddress) {
144
144
  const salt2 = registered.deploymentSalt ?? (await ctx.api.prepare(SURFLIQUID_CHAIN_ID)).salt;
@@ -253,7 +253,7 @@ async function depositSponsored(input) {
253
253
  }
254
254
  async function withdrawSponsored(input) {
255
255
  const { api, chain, wallet, amount } = input;
256
- const registered = await api.getVault(wallet.ownerAddress);
256
+ const registered = await api.getVault(wallet.smartAccountAddress);
257
257
  if (!registered.userVaultAddress) {
258
258
  throw new Error("SurfLiquid has no vault registered for this wallet");
259
259
  }
package/dist/index.cjs CHANGED
@@ -388,7 +388,7 @@ function normalizeSupportedAssets(json, chainId) {
388
388
  function createSurfBroker(options) {
389
389
  const fetchImpl = options.fetchImpl ?? fetch;
390
390
  const now = options.now ?? Date.now;
391
- const base5 = `${options.routingApiBaseUrl.replace(/\/$/, "")}/api/v1/surf`;
391
+ const base4 = `${options.routingApiBaseUrl.replace(/\/$/, "")}/api/v1/surf`;
392
392
  const wallet = options.walletAddress;
393
393
  let session = readSurfSession(options.apiKey, wallet);
394
394
  const vaultMemo = /* @__PURE__ */ new Map();
@@ -407,7 +407,7 @@ function createSurfBroker(options) {
407
407
  if (options.origin) headers["origin"] = options.origin;
408
408
  let response;
409
409
  try {
410
- response = await fetchImpl(`${base5}${path}`, {
410
+ response = await fetchImpl(`${base4}${path}`, {
411
411
  method,
412
412
  headers,
413
413
  body: body === void 0 ? void 0 : JSON.stringify(body),
@@ -501,7 +501,7 @@ function createSurfBroker(options) {
501
501
  )
502
502
  };
503
503
  }
504
- var SURF_SESSION_HEADER, SURF_BROKER_TIMEOUT_MS, VAULT_MEMO_TTL_MS, AGENT_ID, DISCOVERY_WALLET, SurfSessionExpiredError, asRecord, unavailable;
504
+ var SURF_SESSION_HEADER, SURF_BROKER_TIMEOUT_MS, VAULT_MEMO_TTL_MS, AGENT_ID, DISCOVERY_WALLET, SurfSessionExpiredError, asRecord, unavailable, emptyVaultInfo;
505
505
  var init_surfliquid_broker = __esm({
506
506
  "src/agents/surfliquid/surfliquid.broker.ts"() {
507
507
  "use strict";
@@ -520,6 +520,7 @@ var init_surfliquid_broker = __esm({
520
520
  };
521
521
  asRecord = (value) => value && typeof value === "object" ? value : {};
522
522
  unavailable = (message, details) => new OwneyError("SURF_UNAVAILABLE", message, details, AGENT_ID);
523
+ emptyVaultInfo = () => normalizeVault(void 0);
523
524
  }
524
525
  });
525
526
 
@@ -527,7 +528,7 @@ var init_surfliquid_broker = __esm({
527
528
  function mapMessage(message) {
528
529
  const action = SURFLIQUID_ACTION_MAP[message.transactionType];
529
530
  if (!action) return [];
530
- const base5 = {
531
+ const base4 = {
531
532
  agent: "surfliquid",
532
533
  action,
533
534
  date: message.timestamp,
@@ -545,9 +546,9 @@ function mapMessage(message) {
545
546
  };
546
547
  if (DEPOSIT_TRANSACTION_TYPES.has(message.transactionType) && message.toVault?.name && message.amount != null) {
547
548
  return [
548
- base5,
549
+ base4,
549
550
  {
550
- ...base5,
551
+ ...base4,
551
552
  action: "Deposit",
552
553
  positions: [
553
554
  {
@@ -560,10 +561,20 @@ function mapMessage(message) {
560
561
  }
561
562
  ];
562
563
  }
563
- return [base5];
564
+ return [base4];
565
+ }
566
+ function dedupeMessages(messages) {
567
+ const seen = /* @__PURE__ */ new Set();
568
+ return messages.filter((message) => {
569
+ if (!message.txHash) return true;
570
+ const key2 = `${message.transactionType}:${message.txHash}`;
571
+ if (seen.has(key2)) return false;
572
+ seen.add(key2);
573
+ return true;
574
+ });
564
575
  }
565
576
  function mapHistory(result, _chainId) {
566
- const data = result.messages.flatMap(mapMessage);
577
+ const data = dedupeMessages(result.messages).flatMap(mapMessage);
567
578
  const hasMore = result.page < result.pages;
568
579
  return {
569
580
  data,
@@ -760,7 +771,7 @@ var init_surfliquid_calls = __esm({
760
771
 
761
772
  // src/agents/surfliquid/surfliquid.sponsorship.ts
762
773
  async function resolveVault(ctx) {
763
- const registered = await ctx.api.getVault(ctx.wallet.ownerAddress);
774
+ const registered = await ctx.api.getVault(ctx.wallet.smartAccountAddress);
764
775
  const smartAccount = ctx.wallet.smartAccountAddress;
765
776
  if (!registered.userVaultAddress) {
766
777
  const salt2 = registered.deploymentSalt ?? (await ctx.api.prepare(SURFLIQUID_CHAIN_ID)).salt;
@@ -875,7 +886,7 @@ async function depositSponsored(input) {
875
886
  }
876
887
  async function withdrawSponsored(input) {
877
888
  const { api, chain, wallet, amount } = input;
878
- const registered = await api.getVault(wallet.ownerAddress);
889
+ const registered = await api.getVault(wallet.smartAccountAddress);
879
890
  if (!registered.userVaultAddress) {
880
891
  throw new Error("SurfLiquid has no vault registered for this wallet");
881
892
  }
@@ -1077,10 +1088,11 @@ function pinAccount(provider, address) {
1077
1088
  };
1078
1089
  }
1079
1090
  async function createSponsoredWallet(input) {
1080
- const entryPoint = { address: import_account_abstraction.entryPoint08Address, version: "0.8" };
1081
- const account = await (0, import_accounts.toSimpleSmartAccount)({
1091
+ const entryPoint = { address: import_account_abstraction.entryPoint07Address, version: "0.7" };
1092
+ const account = await (0, import_accounts.toSafeSmartAccount)({
1082
1093
  client: publicClientFor(input.rpcUrl),
1083
- owner: pinAccount(input.provider, input.ownerAddress),
1094
+ owners: [pinAccount(input.provider, input.ownerAddress)],
1095
+ version: "1.4.1",
1084
1096
  entryPoint
1085
1097
  });
1086
1098
  const bundlerTransport = (0, import_viem9.http)(sponsorProxyUrl(input.routingApiBaseUrl), {
@@ -1112,6 +1124,20 @@ async function createSponsoredWallet(input) {
1112
1124
  primaryType: typedData.primaryType,
1113
1125
  message: typedData.message
1114
1126
  }),
1127
+ // The smart account signs (ERC-1271), not the EOA: SurfLiquid's SIWE session must
1128
+ // be the vault owner, which is the smart account. Safe wraps this as a SafeMessage
1129
+ // EIP-712 signature the deployed account verifies via isValidSignature.
1130
+ signMessage: (message) => account.signMessage({ message }),
1131
+ // Deploy-on-connect: the account is counterfactual until its first userOp, but SIWE
1132
+ // (isValidSignature) needs on-chain code. A no-op self-call carries the factory
1133
+ // initCode and deploys it. Idempotency is the caller's (it checks isDeployed first).
1134
+ deployAccount: async () => {
1135
+ const userOpHash = await smartAccountClient.sendUserOperation({
1136
+ calls: [{ to: account.address, value: 0n, data: "0x" }]
1137
+ });
1138
+ const receipt = await smartAccountClient.waitForUserOperationReceipt({ hash: userOpHash });
1139
+ return receipt.receipt.transactionHash;
1140
+ },
1115
1141
  sendCalls: async (calls) => {
1116
1142
  const userOpHash = await smartAccountClient.sendUserOperation({
1117
1143
  calls: calls.map((c) => ({ to: c.to, data: c.data, value: 0n }))
@@ -1166,12 +1192,10 @@ function toOwneyError(error) {
1166
1192
  }
1167
1193
  return new OwneyError("SPONSORSHIP_UNAVAILABLE", message, void 0, AGENT_ID2);
1168
1194
  }
1169
- var import_viem10, import_chains3, AGENT_ID2, WALLET_REJECTED_CODE, DISCOVERY_WALLET2, HISTORY_DEFAULT_LIMIT, APY_WINDOW_KEY2, SurfLiquidAgent;
1195
+ var AGENT_ID2, WALLET_REJECTED_CODE, DISCOVERY_WALLET2, HISTORY_DEFAULT_LIMIT, APY_WINDOW_KEY2, SurfLiquidAgent;
1170
1196
  var init_surfliquid_agent = __esm({
1171
1197
  "src/agents/surfliquid/surfliquid.agent.ts"() {
1172
1198
  "use strict";
1173
- import_viem10 = require("viem");
1174
- import_chains3 = require("viem/chains");
1175
1199
  init_errors();
1176
1200
  init_surfliquid_constants();
1177
1201
  init_surfliquid_broker();
@@ -1198,6 +1222,9 @@ var init_surfliquid_agent = __esm({
1198
1222
  supportedAssets = SURFLIQUID_SUPPORTED_ASSETS;
1199
1223
  broker = null;
1200
1224
  brokerWallet = null;
1225
+ // The SurfLiquid session and every keyed read run on the smart account (the vault
1226
+ // owner), not the EOA — set by connect(), consumed by the reads below.
1227
+ smartAccountAddress = null;
1201
1228
  // Dedicated instance for the anonymous "0x" asset probe — never shares a slot
1202
1229
  // with the user's broker, so discovery can never evict or overwrite a session.
1203
1230
  discoveryBroker = null;
@@ -1219,17 +1246,22 @@ var init_surfliquid_agent = __esm({
1219
1246
  return this.broker;
1220
1247
  }
1221
1248
  async connect(state, shouldForce = false) {
1222
- const broker = this.brokerFor(state.walletAddress);
1223
- if (!shouldForce && broker.hasSession()) return broker;
1249
+ if (!shouldForce && this.broker && this.smartAccountAddress && this.broker.hasSession()) {
1250
+ return this.broker;
1251
+ }
1224
1252
  if (this.connectPromise) return this.connectPromise;
1225
1253
  this.connectPromise = (async () => {
1254
+ const wallet = await this.sponsoredWallet(state);
1255
+ const smartAccountAddress = wallet.smartAccountAddress;
1256
+ this.smartAccountAddress = smartAccountAddress;
1257
+ const broker = this.brokerFor(smartAccountAddress);
1258
+ if (!shouldForce && broker.hasSession()) return broker;
1259
+ const { createSponsoredChain: createSponsoredChain2 } = await Promise.resolve().then(() => (init_surfliquid_smart_account(), surfliquid_smart_account_exports));
1260
+ if (!await createSponsoredChain2(this.config.rpcUrl).isDeployed(smartAccountAddress)) {
1261
+ await wallet.deployAccount();
1262
+ }
1226
1263
  const message = await broker.nonce();
1227
- const walletClient = (0, import_viem10.createWalletClient)({
1228
- account: state.walletAddress,
1229
- chain: import_chains3.base,
1230
- transport: (0, import_viem10.custom)(state.provider)
1231
- });
1232
- const signature = await walletClient.signMessage({ account: state.walletAddress, message });
1264
+ const signature = await wallet.signMessage(message);
1233
1265
  await broker.login(message, signature);
1234
1266
  return broker;
1235
1267
  })();
@@ -1239,6 +1271,10 @@ var init_surfliquid_agent = __esm({
1239
1271
  this.connectPromise = null;
1240
1272
  }
1241
1273
  }
1274
+ /** The SurfLiquid-facing wallet address: the smart account once connected, else the EOA. */
1275
+ surfWallet(state) {
1276
+ return this.smartAccountAddress ?? state.walletAddress;
1277
+ }
1242
1278
  /** A 401 can only surface before any signature (SurfLiquid is never called between sign and submit). */
1243
1279
  async withSession(state, run) {
1244
1280
  try {
@@ -1269,9 +1305,22 @@ var init_surfliquid_agent = __esm({
1269
1305
  this.broker?.clearSession();
1270
1306
  this.broker = null;
1271
1307
  this.brokerWallet = null;
1308
+ this.smartAccountAddress = null;
1272
1309
  }
1273
- async activateAgent(state, _chainId) {
1274
- await this.connect(state);
1310
+ // The SDK orchestrator already marks the agent active and sets the chain. SurfLiquid
1311
+ // establishes its session lazily — on the first read of a deployed account, or on
1312
+ // deposit — so merely connecting a wallet never prompts for a signature.
1313
+ async activateAgent(_state, _chainId) {
1314
+ }
1315
+ /** A counterfactual account owns no vault and can't be a SIWE signer yet — reads answer empty. */
1316
+ async isSmartAccountDeployed(state) {
1317
+ if (this.broker?.hasSession()) return true;
1318
+ const wallet = await this.sponsoredWallet(state);
1319
+ this.smartAccountAddress = wallet.smartAccountAddress;
1320
+ const { createSponsoredChain: createSponsoredChain2 } = await Promise.resolve().then(() => (init_surfliquid_smart_account(), surfliquid_smart_account_exports));
1321
+ return createSponsoredChain2(this.config.rpcUrl).isDeployed(
1322
+ wallet.smartAccountAddress
1323
+ );
1275
1324
  }
1276
1325
  // --- IAgent: funds (gasless only) ---
1277
1326
  async deposit(state, _chainId, amount, _asset, _depositCallback) {
@@ -1329,8 +1378,9 @@ var init_surfliquid_agent = __esm({
1329
1378
  }
1330
1379
  // --- IAgent: portfolio reads ---
1331
1380
  async vault(state) {
1381
+ if (!await this.isSmartAccountDeployed(state)) return emptyVaultInfo();
1332
1382
  const broker = await this.connect(state);
1333
- return this.withSession(state, () => broker.getVault(state.walletAddress));
1383
+ return this.withSession(state, () => broker.getVault(this.surfWallet(state)));
1334
1384
  }
1335
1385
  async getBalances(state, chainId) {
1336
1386
  const vault = await this.vault(state);
@@ -1346,12 +1396,13 @@ var init_surfliquid_agent = __esm({
1346
1396
  return mapAccountApy(await this.vault(state), days);
1347
1397
  }
1348
1398
  async getHistory(state, chainId, options) {
1399
+ if (!await this.isSmartAccountDeployed(state)) return { data: [], hasMore: false };
1349
1400
  const broker = await this.connect(state);
1350
1401
  const page = options?.cursor ? Number(options.cursor) : 1;
1351
1402
  const limit = options?.limit ?? HISTORY_DEFAULT_LIMIT;
1352
1403
  const result = await this.withSession(
1353
1404
  state,
1354
- () => broker.getAgentMessages(state.walletAddress, page, limit, options?.fromDate, options?.toDate)
1405
+ () => broker.getAgentMessages(this.surfWallet(state), page, limit, options?.fromDate, options?.toDate)
1355
1406
  );
1356
1407
  return mapHistory(result, chainId);
1357
1408
  }
@@ -3590,8 +3641,8 @@ function aggregateApyByChainAndAsset(agentApys, agentBalances) {
3590
3641
  }
3591
3642
 
3592
3643
  // src/client.ts
3593
- var import_viem11 = require("viem");
3594
- var import_chains4 = require("viem/chains");
3644
+ var import_viem10 = require("viem");
3645
+ var import_chains3 = require("viem/chains");
3595
3646
 
3596
3647
  // src/lib/sponsored-deposit.ts
3597
3648
  init_errors();
@@ -3601,10 +3652,10 @@ init_transfer_auth();
3601
3652
  init_errors();
3602
3653
  var ROUTING_API_BASE_URL3 = "https://owney-routing-api-243946518160.europe-west4.run.app";
3603
3654
  async function postSponsorTransferAuth(input) {
3604
- const base5 = input.baseUrl ?? ROUTING_API_BASE_URL3;
3655
+ const base4 = input.baseUrl ?? ROUTING_API_BASE_URL3;
3605
3656
  let res;
3606
3657
  try {
3607
- res = await fetch(`${base5}/api/v1/sponsor/erc20-transfer-auth`, {
3658
+ res = await fetch(`${base4}/api/v1/sponsor/erc20-transfer-auth`, {
3608
3659
  method: "POST",
3609
3660
  headers: {
3610
3661
  "content-type": "application/json",
@@ -3641,10 +3692,10 @@ async function postSponsorTransferAuth(input) {
3641
3692
  return parsed.data;
3642
3693
  }
3643
3694
  async function postSponsorPermit2Transfer(input) {
3644
- const base5 = input.baseUrl ?? ROUTING_API_BASE_URL3;
3695
+ const base4 = input.baseUrl ?? ROUTING_API_BASE_URL3;
3645
3696
  let res;
3646
3697
  try {
3647
- res = await fetch(`${base5}/api/v1/sponsor/permit2-transfer`, {
3698
+ res = await fetch(`${base4}/api/v1/sponsor/permit2-transfer`, {
3648
3699
  method: "POST",
3649
3700
  headers: {
3650
3701
  "content-type": "application/json",
@@ -3679,11 +3730,11 @@ async function postSponsorPermit2Transfer(input) {
3679
3730
  return parsed.data;
3680
3731
  }
3681
3732
  async function getSponsorRelayerAddress(input) {
3682
- const base5 = input.baseUrl ?? ROUTING_API_BASE_URL3;
3733
+ const base4 = input.baseUrl ?? ROUTING_API_BASE_URL3;
3683
3734
  let res;
3684
3735
  try {
3685
3736
  res = await fetch(
3686
- `${base5}/api/v1/sponsor/relayer-address?chainId=${input.chainId}`,
3737
+ `${base4}/api/v1/sponsor/relayer-address?chainId=${input.chainId}`,
3687
3738
  {
3688
3739
  headers: { "x-owney-api-key": input.apiKey }
3689
3740
  }
@@ -4110,9 +4161,9 @@ var SPONSORED_USDC_BY_CHAIN = {
4110
4161
  1: "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"
4111
4162
  };
4112
4163
  var VIEM_CHAIN2 = {
4113
- 8453: import_chains4.base,
4114
- 42161: import_chains4.arbitrum,
4115
- 1: import_chains4.mainnet
4164
+ 8453: import_chains3.base,
4165
+ 42161: import_chains3.arbitrum,
4166
+ 1: import_chains3.mainnet
4116
4167
  };
4117
4168
  var SPONSORED_WETH_BY_CHAIN = {
4118
4169
  8453: "0x4200000000000000000000000000000000000006",
@@ -4269,14 +4320,14 @@ var OwneySDK = class {
4269
4320
  // Casts work around viem's chain-narrowed Client vs the generic
4270
4321
  // PublicClient/WalletClient param types — structurally identical at
4271
4322
  // runtime, but the two share a name TS treats as unrelated.
4272
- getPublicClient: (cid) => (0, import_viem11.createPublicClient)({
4323
+ getPublicClient: (cid) => (0, import_viem10.createPublicClient)({
4273
4324
  chain: VIEM_CHAIN2[cid],
4274
- transport: (0, import_viem11.custom)(provider)
4325
+ transport: (0, import_viem10.custom)(provider)
4275
4326
  }),
4276
- getWalletClient: (cid) => (0, import_viem11.createWalletClient)({
4327
+ getWalletClient: (cid) => (0, import_viem10.createWalletClient)({
4277
4328
  account: owner,
4278
4329
  chain: VIEM_CHAIN2[cid],
4279
- transport: (0, import_viem11.custom)(provider)
4330
+ transport: (0, import_viem10.custom)(provider)
4280
4331
  })
4281
4332
  });
4282
4333
  if (!onApproved) this.cachedSponsoredCallback = callback;
@@ -4322,14 +4373,14 @@ var OwneySDK = class {
4322
4373
  // Casts work around viem's chain-narrowed Client vs the generic
4323
4374
  // PublicClient/WalletClient param types — structurally identical at
4324
4375
  // runtime, but the two share a name TS treats as unrelated.
4325
- getPublicClient: (cid) => (0, import_viem11.createPublicClient)({
4376
+ getPublicClient: (cid) => (0, import_viem10.createPublicClient)({
4326
4377
  chain: VIEM_CHAIN2[cid],
4327
- transport: (0, import_viem11.custom)(provider)
4378
+ transport: (0, import_viem10.custom)(provider)
4328
4379
  }),
4329
- getWalletClient: (cid) => (0, import_viem11.createWalletClient)({
4380
+ getWalletClient: (cid) => (0, import_viem10.createWalletClient)({
4330
4381
  account: owner,
4331
4382
  chain: VIEM_CHAIN2[cid],
4332
- transport: (0, import_viem11.custom)(provider)
4383
+ transport: (0, import_viem10.custom)(provider)
4333
4384
  })
4334
4385
  });
4335
4386
  if (!onApproved) this.cachedWethSponsoredCallback = callback;
@@ -5448,10 +5499,10 @@ var OwneySDK = class {
5448
5499
  );
5449
5500
  }
5450
5501
  const provider = this.requireConnectedProvider();
5451
- const wallet = (0, import_viem11.createWalletClient)({
5502
+ const wallet = (0, import_viem10.createWalletClient)({
5452
5503
  account: state.walletAddress,
5453
5504
  chain: VIEM_CHAIN2[chainId],
5454
- transport: (0, import_viem11.custom)(provider)
5505
+ transport: (0, import_viem10.custom)(provider)
5455
5506
  });
5456
5507
  const hash = await wallet.writeContract({
5457
5508
  address: token,
@@ -5461,9 +5512,9 @@ var OwneySDK = class {
5461
5512
  account: state.walletAddress,
5462
5513
  chain: VIEM_CHAIN2[chainId]
5463
5514
  });
5464
- const publicClient = (0, import_viem11.createPublicClient)({
5515
+ const publicClient = (0, import_viem10.createPublicClient)({
5465
5516
  chain: VIEM_CHAIN2[chainId],
5466
- transport: (0, import_viem11.custom)(provider)
5517
+ transport: (0, import_viem10.custom)(provider)
5467
5518
  });
5468
5519
  const receipt = await publicClient.waitForTransactionReceipt({
5469
5520
  hash,
@@ -5579,7 +5630,7 @@ init_errors();
5579
5630
  init_debug();
5580
5631
 
5581
5632
  // src/agents/zyfai/zyfai.siwx.ts
5582
- var import_viem12 = require("viem");
5633
+ var import_viem11 = require("viem");
5583
5634
  var import_siwe = require("siwe");
5584
5635
  var import_sdk2 = require("@zyfai/sdk");
5585
5636
 
@@ -5706,7 +5757,7 @@ function buildSIWXConfig(deps) {
5706
5757
  issuedAt,
5707
5758
  toString() {
5708
5759
  return new import_siwe.SiweMessage({
5709
- address: (0, import_viem12.getAddress)(accountAddress),
5760
+ address: (0, import_viem11.getAddress)(accountAddress),
5710
5761
  chainId: numericChainId(chainId),
5711
5762
  domain,
5712
5763
  uri,
package/dist/index.js CHANGED
@@ -3036,7 +3036,7 @@ var OwneySDK = class {
3036
3036
  }
3037
3037
  if (agentId === "surfliquid") {
3038
3038
  if (!key2) return null;
3039
- const { SurfLiquidAgent } = await import("./surfliquid.agent-BFBNEQQI.js");
3039
+ const { SurfLiquidAgent } = await import("./surfliquid.agent-YC4VDPPF.js");
3040
3040
  return new SurfLiquidAgent({
3041
3041
  apiKey: this.apiKey,
3042
3042
  routingApiBaseUrl: this.routingApiBaseUrl
@@ -13,13 +13,9 @@ import {
13
13
  readStuckBalance,
14
14
  sweepStuckBalance,
15
15
  withdrawSponsored
16
- } from "./chunk-5W56YOBO.js";
16
+ } from "./chunk-T5YJVIQG.js";
17
17
  import "./chunk-AURO3C3R.js";
18
18
 
19
- // src/agents/surfliquid/surfliquid.agent.ts
20
- import { createWalletClient, custom } from "viem";
21
- import { base } from "viem/chains";
22
-
23
19
  // src/agents/surfliquid/surfliquid.session-store.ts
24
20
  var KEY_PREFIX = "owney.surfliquid.session";
25
21
  var EXPIRY_SKEW_MS = 3e4;
@@ -100,6 +96,7 @@ function parseJson(text) {
100
96
  return void 0;
101
97
  }
102
98
  }
99
+ var emptyVaultInfo = () => normalizeVault(void 0);
103
100
  function normalizeVault(json) {
104
101
  const root = asRecord(json);
105
102
  const data = asRecord(root.data);
@@ -146,7 +143,7 @@ function normalizeSupportedAssets(json, chainId) {
146
143
  function createSurfBroker(options) {
147
144
  const fetchImpl = options.fetchImpl ?? fetch;
148
145
  const now = options.now ?? Date.now;
149
- const base2 = `${options.routingApiBaseUrl.replace(/\/$/, "")}/api/v1/surf`;
146
+ const base = `${options.routingApiBaseUrl.replace(/\/$/, "")}/api/v1/surf`;
150
147
  const wallet = options.walletAddress;
151
148
  let session = readSurfSession(options.apiKey, wallet);
152
149
  const vaultMemo = /* @__PURE__ */ new Map();
@@ -165,7 +162,7 @@ function createSurfBroker(options) {
165
162
  if (options.origin) headers["origin"] = options.origin;
166
163
  let response;
167
164
  try {
168
- response = await fetchImpl(`${base2}${path}`, {
165
+ response = await fetchImpl(`${base}${path}`, {
169
166
  method,
170
167
  headers,
171
168
  body: body === void 0 ? void 0 : JSON.stringify(body),
@@ -270,7 +267,7 @@ var DEPOSIT_TRANSACTION_TYPES = /* @__PURE__ */ new Set([
270
267
  function mapMessage(message) {
271
268
  const action = SURFLIQUID_ACTION_MAP[message.transactionType];
272
269
  if (!action) return [];
273
- const base2 = {
270
+ const base = {
274
271
  agent: "surfliquid",
275
272
  action,
276
273
  date: message.timestamp,
@@ -288,9 +285,9 @@ function mapMessage(message) {
288
285
  };
289
286
  if (DEPOSIT_TRANSACTION_TYPES.has(message.transactionType) && message.toVault?.name && message.amount != null) {
290
287
  return [
291
- base2,
288
+ base,
292
289
  {
293
- ...base2,
290
+ ...base,
294
291
  action: "Deposit",
295
292
  positions: [
296
293
  {
@@ -303,10 +300,20 @@ function mapMessage(message) {
303
300
  }
304
301
  ];
305
302
  }
306
- return [base2];
303
+ return [base];
304
+ }
305
+ function dedupeMessages(messages) {
306
+ const seen = /* @__PURE__ */ new Set();
307
+ return messages.filter((message) => {
308
+ if (!message.txHash) return true;
309
+ const key = `${message.transactionType}:${message.txHash}`;
310
+ if (seen.has(key)) return false;
311
+ seen.add(key);
312
+ return true;
313
+ });
307
314
  }
308
315
  function mapHistory(result, _chainId) {
309
- const data = result.messages.flatMap(mapMessage);
316
+ const data = dedupeMessages(result.messages).flatMap(mapMessage);
310
317
  const hasMore = result.page < result.pages;
311
318
  return {
312
319
  data,
@@ -502,6 +509,9 @@ var SurfLiquidAgent = class {
502
509
  supportedAssets = SURFLIQUID_SUPPORTED_ASSETS;
503
510
  broker = null;
504
511
  brokerWallet = null;
512
+ // The SurfLiquid session and every keyed read run on the smart account (the vault
513
+ // owner), not the EOA — set by connect(), consumed by the reads below.
514
+ smartAccountAddress = null;
505
515
  // Dedicated instance for the anonymous "0x" asset probe — never shares a slot
506
516
  // with the user's broker, so discovery can never evict or overwrite a session.
507
517
  discoveryBroker = null;
@@ -523,17 +533,22 @@ var SurfLiquidAgent = class {
523
533
  return this.broker;
524
534
  }
525
535
  async connect(state, shouldForce = false) {
526
- const broker = this.brokerFor(state.walletAddress);
527
- if (!shouldForce && broker.hasSession()) return broker;
536
+ if (!shouldForce && this.broker && this.smartAccountAddress && this.broker.hasSession()) {
537
+ return this.broker;
538
+ }
528
539
  if (this.connectPromise) return this.connectPromise;
529
540
  this.connectPromise = (async () => {
541
+ const wallet = await this.sponsoredWallet(state);
542
+ const smartAccountAddress = wallet.smartAccountAddress;
543
+ this.smartAccountAddress = smartAccountAddress;
544
+ const broker = this.brokerFor(smartAccountAddress);
545
+ if (!shouldForce && broker.hasSession()) return broker;
546
+ const { createSponsoredChain } = await import("./surfliquid.smart-account-YV3PLZ72.js");
547
+ if (!await createSponsoredChain(this.config.rpcUrl).isDeployed(smartAccountAddress)) {
548
+ await wallet.deployAccount();
549
+ }
530
550
  const message = await broker.nonce();
531
- const walletClient = createWalletClient({
532
- account: state.walletAddress,
533
- chain: base,
534
- transport: custom(state.provider)
535
- });
536
- const signature = await walletClient.signMessage({ account: state.walletAddress, message });
551
+ const signature = await wallet.signMessage(message);
537
552
  await broker.login(message, signature);
538
553
  return broker;
539
554
  })();
@@ -543,6 +558,10 @@ var SurfLiquidAgent = class {
543
558
  this.connectPromise = null;
544
559
  }
545
560
  }
561
+ /** The SurfLiquid-facing wallet address: the smart account once connected, else the EOA. */
562
+ surfWallet(state) {
563
+ return this.smartAccountAddress ?? state.walletAddress;
564
+ }
546
565
  /** A 401 can only surface before any signature (SurfLiquid is never called between sign and submit). */
547
566
  async withSession(state, run) {
548
567
  try {
@@ -559,7 +578,7 @@ var SurfLiquidAgent = class {
559
578
  }
560
579
  }
561
580
  async sponsoredWallet(state) {
562
- const { createSponsoredWallet } = await import("./surfliquid.smart-account-O6YPCQT3.js");
581
+ const { createSponsoredWallet } = await import("./surfliquid.smart-account-YV3PLZ72.js");
563
582
  return createSponsoredWallet({
564
583
  provider: state.provider,
565
584
  ownerAddress: state.walletAddress,
@@ -573,15 +592,28 @@ var SurfLiquidAgent = class {
573
592
  this.broker?.clearSession();
574
593
  this.broker = null;
575
594
  this.brokerWallet = null;
595
+ this.smartAccountAddress = null;
596
+ }
597
+ // The SDK orchestrator already marks the agent active and sets the chain. SurfLiquid
598
+ // establishes its session lazily — on the first read of a deployed account, or on
599
+ // deposit — so merely connecting a wallet never prompts for a signature.
600
+ async activateAgent(_state, _chainId) {
576
601
  }
577
- async activateAgent(state, _chainId) {
578
- await this.connect(state);
602
+ /** A counterfactual account owns no vault and can't be a SIWE signer yet — reads answer empty. */
603
+ async isSmartAccountDeployed(state) {
604
+ if (this.broker?.hasSession()) return true;
605
+ const wallet = await this.sponsoredWallet(state);
606
+ this.smartAccountAddress = wallet.smartAccountAddress;
607
+ const { createSponsoredChain } = await import("./surfliquid.smart-account-YV3PLZ72.js");
608
+ return createSponsoredChain(this.config.rpcUrl).isDeployed(
609
+ wallet.smartAccountAddress
610
+ );
579
611
  }
580
612
  // --- IAgent: funds (gasless only) ---
581
613
  async deposit(state, _chainId, amount, _asset, _depositCallback) {
582
614
  const broker = await this.connect(state);
583
615
  const wallet = await this.sponsoredWallet(state);
584
- const { createSponsoredChain } = await import("./surfliquid.smart-account-O6YPCQT3.js");
616
+ const { createSponsoredChain } = await import("./surfliquid.smart-account-YV3PLZ72.js");
585
617
  try {
586
618
  const { txHash, vault } = await this.withSession(
587
619
  state,
@@ -596,7 +628,7 @@ var SurfLiquidAgent = class {
596
628
  async withdraw(state, _chainId, _token, amount) {
597
629
  const broker = await this.connect(state);
598
630
  const wallet = await this.sponsoredWallet(state);
599
- const { createSponsoredChain } = await import("./surfliquid.smart-account-O6YPCQT3.js");
631
+ const { createSponsoredChain } = await import("./surfliquid.smart-account-YV3PLZ72.js");
600
632
  try {
601
633
  const result = await this.withSession(
602
634
  state,
@@ -616,14 +648,14 @@ var SurfLiquidAgent = class {
616
648
  /** Funds a prior withdrawal's sweep left in the smart account (never reached the EOA). No session needed — pure read. */
617
649
  async getStuckBalance(state) {
618
650
  const wallet = await this.sponsoredWallet(state);
619
- const { createSponsoredChain } = await import("./surfliquid.smart-account-O6YPCQT3.js");
651
+ const { createSponsoredChain } = await import("./surfliquid.smart-account-YV3PLZ72.js");
620
652
  const amount = await readStuckBalance({ chain: createSponsoredChain(this.config.rpcUrl), wallet });
621
653
  return { amount: amount.toString(), smartAccountAddress: wallet.smartAccountAddress };
622
654
  }
623
655
  /** Sweep the stranded balance to the owner's EOA — one sponsored userOp, one signature. */
624
656
  async recoverStuckBalance(state) {
625
657
  const wallet = await this.sponsoredWallet(state);
626
- const { createSponsoredChain } = await import("./surfliquid.smart-account-O6YPCQT3.js");
658
+ const { createSponsoredChain } = await import("./surfliquid.smart-account-YV3PLZ72.js");
627
659
  try {
628
660
  const { txHash, amount } = await sweepStuckBalance({ chain: createSponsoredChain(this.config.rpcUrl), wallet });
629
661
  return { txHash, type: "full", amount: amount.toString() };
@@ -633,8 +665,9 @@ var SurfLiquidAgent = class {
633
665
  }
634
666
  // --- IAgent: portfolio reads ---
635
667
  async vault(state) {
668
+ if (!await this.isSmartAccountDeployed(state)) return emptyVaultInfo();
636
669
  const broker = await this.connect(state);
637
- return this.withSession(state, () => broker.getVault(state.walletAddress));
670
+ return this.withSession(state, () => broker.getVault(this.surfWallet(state)));
638
671
  }
639
672
  async getBalances(state, chainId) {
640
673
  const vault = await this.vault(state);
@@ -650,12 +683,13 @@ var SurfLiquidAgent = class {
650
683
  return mapAccountApy(await this.vault(state), days);
651
684
  }
652
685
  async getHistory(state, chainId, options) {
686
+ if (!await this.isSmartAccountDeployed(state)) return { data: [], hasMore: false };
653
687
  const broker = await this.connect(state);
654
688
  const page = options?.cursor ? Number(options.cursor) : 1;
655
689
  const limit = options?.limit ?? HISTORY_DEFAULT_LIMIT;
656
690
  const result = await this.withSession(
657
691
  state,
658
- () => broker.getAgentMessages(state.walletAddress, page, limit, options?.fromDate, options?.toDate)
692
+ () => broker.getAgentMessages(this.surfWallet(state), page, limit, options?.fromDate, options?.toDate)
659
693
  );
660
694
  return mapHistory(result, chainId);
661
695
  }
@@ -6,14 +6,14 @@ import {
6
6
  SURFLIQUID_VAULT_ABI,
7
7
  SubmittedError,
8
8
  USDC_ABI
9
- } from "./chunk-5W56YOBO.js";
9
+ } from "./chunk-T5YJVIQG.js";
10
10
  import {
11
11
  readTokenMeta
12
12
  } from "./chunk-AURO3C3R.js";
13
13
 
14
14
  // src/agents/surfliquid/surfliquid.smart-account.ts
15
15
  import { createSmartAccountClient } from "permissionless";
16
- import { toSimpleSmartAccount } from "permissionless/accounts";
16
+ import { toSafeSmartAccount } from "permissionless/accounts";
17
17
  import { createPimlicoClient } from "permissionless/clients/pimlico";
18
18
  import {
19
19
  createPublicClient,
@@ -21,7 +21,7 @@ import {
21
21
  custom,
22
22
  http
23
23
  } from "viem";
24
- import { entryPoint08Address } from "viem/account-abstraction";
24
+ import { entryPoint07Address } from "viem/account-abstraction";
25
25
  import { base } from "viem/chains";
26
26
  var sponsorProxyUrl = (routingApiBaseUrl) => `${routingApiBaseUrl.replace(/\/$/, "")}/api/v1/sponsor/pimlico-rpc/${SURFLIQUID_CHAIN_ID}`;
27
27
  function publicClientFor(rpcUrl) {
@@ -77,10 +77,11 @@ function pinAccount(provider, address) {
77
77
  };
78
78
  }
79
79
  async function createSponsoredWallet(input) {
80
- const entryPoint = { address: entryPoint08Address, version: "0.8" };
81
- const account = await toSimpleSmartAccount({
80
+ const entryPoint = { address: entryPoint07Address, version: "0.7" };
81
+ const account = await toSafeSmartAccount({
82
82
  client: publicClientFor(input.rpcUrl),
83
- owner: pinAccount(input.provider, input.ownerAddress),
83
+ owners: [pinAccount(input.provider, input.ownerAddress)],
84
+ version: "1.4.1",
84
85
  entryPoint
85
86
  });
86
87
  const bundlerTransport = http(sponsorProxyUrl(input.routingApiBaseUrl), {
@@ -112,6 +113,20 @@ async function createSponsoredWallet(input) {
112
113
  primaryType: typedData.primaryType,
113
114
  message: typedData.message
114
115
  }),
116
+ // The smart account signs (ERC-1271), not the EOA: SurfLiquid's SIWE session must
117
+ // be the vault owner, which is the smart account. Safe wraps this as a SafeMessage
118
+ // EIP-712 signature the deployed account verifies via isValidSignature.
119
+ signMessage: (message) => account.signMessage({ message }),
120
+ // Deploy-on-connect: the account is counterfactual until its first userOp, but SIWE
121
+ // (isValidSignature) needs on-chain code. A no-op self-call carries the factory
122
+ // initCode and deploys it. Idempotency is the caller's (it checks isDeployed first).
123
+ deployAccount: async () => {
124
+ const userOpHash = await smartAccountClient.sendUserOperation({
125
+ calls: [{ to: account.address, value: 0n, data: "0x" }]
126
+ });
127
+ const receipt = await smartAccountClient.waitForUserOperationReceipt({ hash: userOpHash });
128
+ return receipt.receipt.transactionHash;
129
+ },
115
130
  sendCalls: async (calls) => {
116
131
  const userOpHash = await smartAccountClient.sendUserOperation({
117
132
  calls: calls.map((c) => ({ to: c.to, data: c.data, value: 0n }))
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@owney/sdk",
3
- "version": "0.7.22-beta.3",
3
+ "version": "0.7.22-beta.5",
4
4
  "type": "module",
5
5
  "main": "dist/index.cjs",
6
6
  "module": "dist/index.js",