@owney/sdk 0.7.22-beta.0 → 0.7.22-beta.2

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.
@@ -1,12 +1,13 @@
1
1
  import {
2
- buildReceiveWithAuthorizationTypedData,
3
- randomAuthNonce
4
- } from "./chunk-5LU2SHO7.js";
2
+ buildPermitTypedData
3
+ } from "./chunk-AURO3C3R.js";
5
4
 
6
5
  // src/agents/surfliquid/surfliquid.constants.ts
7
6
  var SURFLIQUID_CHAIN_ID = 8453;
8
7
  var SURFLIQUID_CHAIN_NAME = "BASE";
9
8
  var SURFLIQUID_USDC_ADDRESS = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
9
+ var SURFLIQUID_PERMIT_CAP = 10000000000n;
10
+ var SURFLIQUID_PERMIT_TTL_SECONDS = 3600n;
10
11
  var SURFLIQUID_MIN_DEPOSIT = "0";
11
12
  var SURFLIQUID_SUPPORTED_ASSETS = [
12
13
  {
@@ -49,10 +50,16 @@ var SURFLIQUID_VAULT_ABI = parseAbi([
49
50
  var USDC_ABI = parseAbi([
50
51
  "function approve(address spender, uint256 amount)",
51
52
  "function transfer(address to, uint256 amount)",
53
+ "function transferFrom(address from, address to, uint256 value)",
52
54
  "function balanceOf(address account) view returns (uint256)",
53
- "function receiveWithAuthorization(address from, address to, uint256 value, uint256 validAfter, uint256 validBefore, bytes32 nonce, bytes signature)"
55
+ "function allowance(address owner, address spender) view returns (uint256)",
56
+ "function nonces(address owner) view returns (uint256)",
57
+ "function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)"
54
58
  ]);
55
59
 
60
+ // src/agents/surfliquid/surfliquid.sponsorship.ts
61
+ import { parseSignature } from "viem";
62
+
56
63
  // src/agents/surfliquid/surfliquid.calls.ts
57
64
  import { encodeFunctionData } from "viem";
58
65
  var call = (to, abi, functionName, args) => ({
@@ -60,12 +67,12 @@ var call = (to, abi, functionName, args) => ({
60
67
  data: encodeFunctionData({ abi, functionName, args })
61
68
  });
62
69
  function buildDepositCalls(input) {
63
- const { smartAccount, vault, amount, authorization, deploySalt } = input;
64
- if (authorization.to.toLowerCase() !== smartAccount.toLowerCase()) {
65
- throw new Error("Transfer authorization must pay the smart account");
70
+ const { smartAccount, owner, vault, amount, permit, deploySalt } = input;
71
+ if (permit && permit.owner.toLowerCase() !== owner.toLowerCase()) {
72
+ throw new Error("Permit must be signed by the smart account's owner");
66
73
  }
67
- if (authorization.value < amount) {
68
- throw new Error("Transfer authorization is worth less than the deposit");
74
+ if (permit && permit.value < amount) {
75
+ throw new Error("Permit allowance is worth less than the deposit");
69
76
  }
70
77
  if (!input.hasInitialDeposit && !input.morphoVault) {
71
78
  throw new Error("A first deposit needs a target morpho vault");
@@ -79,16 +86,21 @@ function buildDepositCalls(input) {
79
86
  ])
80
87
  );
81
88
  }
89
+ if (permit) {
90
+ calls.push(
91
+ call(SURFLIQUID_USDC_ADDRESS, USDC_ABI, "permit", [
92
+ permit.owner,
93
+ smartAccount,
94
+ permit.value,
95
+ permit.deadline,
96
+ permit.v,
97
+ permit.r,
98
+ permit.s
99
+ ])
100
+ );
101
+ }
82
102
  calls.push(
83
- call(SURFLIQUID_USDC_ADDRESS, USDC_ABI, "receiveWithAuthorization", [
84
- authorization.from,
85
- authorization.to,
86
- authorization.value,
87
- authorization.validAfter,
88
- authorization.validBefore,
89
- authorization.nonce,
90
- authorization.signature
91
- ]),
103
+ call(SURFLIQUID_USDC_ADDRESS, USDC_ABI, "transferFrom", [owner, smartAccount, amount]),
92
104
  call(SURFLIQUID_USDC_ADDRESS, USDC_ABI, "approve", [vault, amount]),
93
105
  input.hasInitialDeposit ? call(vault, SURFLIQUID_VAULT_ABI, "userDeposit", [SURFLIQUID_USDC_ADDRESS, amount]) : call(vault, SURFLIQUID_VAULT_ABI, "initialDeposit", [
94
106
  SURFLIQUID_USDC_ADDRESS,
@@ -111,7 +123,6 @@ function buildSweepCalls(input) {
111
123
  }
112
124
 
113
125
  // src/agents/surfliquid/surfliquid.sponsorship.ts
114
- var AUTHORIZATION_TTL_SECONDS = 3600n;
115
126
  var SubmittedError = class extends Error {
116
127
  constructor(message, userOpHash) {
117
128
  super(message);
@@ -160,22 +171,23 @@ async function pickMorphoVault(api) {
160
171
  }
161
172
  return candidate.vaultAddress;
162
173
  }
163
- async function depositSponsored(input) {
164
- const { api, chain, wallet, amount } = input;
165
- const { vault, deploySalt, registerAfterDeposit } = await resolveVault(input);
166
- const hasInitialDeposit = deploySalt ? false : await chain.hasInitialDeposit(vault, SURFLIQUID_USDC_ADDRESS);
167
- const morphoVault = hasInitialDeposit ? void 0 : await pickMorphoVault(api);
168
- const { tokenName, tokenVersion } = await chain.readTokenMeta();
174
+ async function permitIfShort(input) {
175
+ const { chain, wallet, amount } = input;
176
+ const allowance = await chain.readAllowance(wallet.ownerAddress, wallet.smartAccountAddress);
177
+ if (allowance >= amount) return void 0;
178
+ const [{ tokenName, tokenVersion }, nonce] = await Promise.all([
179
+ chain.readTokenMeta(),
180
+ chain.readPermitNonce(wallet.ownerAddress)
181
+ ]);
169
182
  const message = {
170
- from: wallet.ownerAddress,
171
- to: wallet.smartAccountAddress,
172
- value: amount,
173
- validAfter: 0n,
174
- validBefore: BigInt(Math.floor(Date.now() / 1e3)) + AUTHORIZATION_TTL_SECONDS,
175
- nonce: randomAuthNonce()
183
+ owner: wallet.ownerAddress,
184
+ spender: wallet.smartAccountAddress,
185
+ value: amount > SURFLIQUID_PERMIT_CAP ? amount : SURFLIQUID_PERMIT_CAP,
186
+ nonce,
187
+ deadline: BigInt(Math.floor(Date.now() / 1e3)) + SURFLIQUID_PERMIT_TTL_SECONDS
176
188
  };
177
- const signature = await wallet.signTransferAuthorization(
178
- buildReceiveWithAuthorizationTypedData({
189
+ const signature = await wallet.signPermit(
190
+ buildPermitTypedData({
179
191
  token: SURFLIQUID_USDC_ADDRESS,
180
192
  chainId: SURFLIQUID_CHAIN_ID,
181
193
  tokenName,
@@ -183,12 +195,40 @@ async function depositSponsored(input) {
183
195
  message
184
196
  })
185
197
  );
198
+ const { r, s, v, yParity } = parseSignature(signature);
199
+ return {
200
+ owner: message.owner,
201
+ value: message.value,
202
+ deadline: message.deadline,
203
+ v: Number(v ?? BigInt(yParity + 27)),
204
+ r,
205
+ s
206
+ };
207
+ }
208
+ async function readStuckBalance(input) {
209
+ return input.chain.usdcBalanceOf(input.wallet.smartAccountAddress);
210
+ }
211
+ async function sweepStuckBalance(input) {
212
+ const stranded = await readStuckBalance(input);
213
+ if (stranded === 0n) return { amount: 0n };
214
+ const txHash = await input.wallet.sendCalls(
215
+ buildSweepCalls({ owner: input.wallet.ownerAddress, amount: stranded })
216
+ );
217
+ return { txHash, amount: stranded };
218
+ }
219
+ async function depositSponsored(input) {
220
+ const { api, chain, wallet, amount } = input;
221
+ const { vault, deploySalt, registerAfterDeposit } = await resolveVault(input);
222
+ const hasInitialDeposit = deploySalt ? false : await chain.hasInitialDeposit(vault, SURFLIQUID_USDC_ADDRESS);
223
+ const morphoVault = hasInitialDeposit ? void 0 : await pickMorphoVault(api);
224
+ const permit = await permitIfShort({ chain, wallet, amount });
186
225
  const txHash = await wallet.sendCalls(
187
226
  buildDepositCalls({
188
227
  smartAccount: wallet.smartAccountAddress,
228
+ owner: wallet.ownerAddress,
189
229
  vault,
190
230
  amount,
191
- authorization: { ...message, signature },
231
+ permit,
192
232
  hasInitialDeposit,
193
233
  morphoVault,
194
234
  deploySalt
@@ -222,7 +262,15 @@ async function withdrawSponsored(input) {
222
262
  if (owner.toLowerCase() !== wallet.smartAccountAddress.toLowerCase()) {
223
263
  throw new VaultNotSponsorableError(`SurfLiquid vault ${vault} is not owned by the smart account`);
224
264
  }
225
- const withdrawHash = await wallet.sendCalls(buildWithdrawCalls({ vault, amount }));
265
+ let withdrawHash;
266
+ try {
267
+ withdrawHash = await wallet.sendCalls(buildWithdrawCalls({ vault, amount }));
268
+ } catch (redeemError) {
269
+ const stranded = await chain.usdcBalanceOf(wallet.smartAccountAddress);
270
+ if (stranded === 0n) throw redeemError;
271
+ const sweepHash = await wallet.sendCalls(buildSweepCalls({ owner: wallet.ownerAddress, amount: stranded }));
272
+ return { txHash: sweepHash, amount: stranded.toString() };
273
+ }
226
274
  try {
227
275
  const proceeds = await chain.usdcBalanceOf(wallet.smartAccountAddress);
228
276
  if (proceeds === 0n) return { txHash: withdrawHash, amount: "0" };
@@ -249,6 +297,8 @@ export {
249
297
  USDC_ABI,
250
298
  SubmittedError,
251
299
  VaultNotSponsorableError,
300
+ readStuckBalance,
301
+ sweepStuckBalance,
252
302
  depositSponsored,
253
303
  withdrawSponsored
254
304
  };
@@ -21,14 +21,6 @@ function buildTransferWithAuthorizationTypedData(input) {
21
21
  message: input.message
22
22
  };
23
23
  }
24
- function buildReceiveWithAuthorizationTypedData(input) {
25
- const transfer = buildTransferWithAuthorizationTypedData(input);
26
- return {
27
- ...transfer,
28
- types: { ReceiveWithAuthorization: transfer.types.TransferWithAuthorization },
29
- primaryType: "ReceiveWithAuthorization"
30
- };
31
- }
32
24
  async function readTokenMeta(publicClient, token) {
33
25
  const [tokenName, tokenVersion] = await Promise.all([
34
26
  publicClient.readContract({ address: token, abi: ERC20_META_ABI, functionName: "name" }),
@@ -41,10 +33,26 @@ function randomAuthNonce() {
41
33
  globalThis.crypto.getRandomValues(bytes);
42
34
  return bytesToHex(bytes);
43
35
  }
36
+ function buildPermitTypedData(input) {
37
+ return {
38
+ domain: { name: input.tokenName, version: input.tokenVersion, chainId: input.chainId, verifyingContract: input.token },
39
+ types: {
40
+ Permit: [
41
+ { name: "owner", type: "address" },
42
+ { name: "spender", type: "address" },
43
+ { name: "value", type: "uint256" },
44
+ { name: "nonce", type: "uint256" },
45
+ { name: "deadline", type: "uint256" }
46
+ ]
47
+ },
48
+ primaryType: "Permit",
49
+ message: input.message
50
+ };
51
+ }
44
52
 
45
53
  export {
46
54
  buildTransferWithAuthorizationTypedData,
47
- buildReceiveWithAuthorizationTypedData,
48
55
  readTokenMeta,
49
- randomAuthNonce
56
+ randomAuthNonce,
57
+ buildPermitTypedData
50
58
  };
package/dist/index.cjs CHANGED
@@ -193,14 +193,6 @@ function buildTransferWithAuthorizationTypedData(input) {
193
193
  message: input.message
194
194
  };
195
195
  }
196
- function buildReceiveWithAuthorizationTypedData(input) {
197
- const transfer = buildTransferWithAuthorizationTypedData(input);
198
- return {
199
- ...transfer,
200
- types: { ReceiveWithAuthorization: transfer.types.TransferWithAuthorization },
201
- primaryType: "ReceiveWithAuthorization"
202
- };
203
- }
204
196
  async function readTokenMeta(publicClient, token) {
205
197
  const [tokenName, tokenVersion] = await Promise.all([
206
198
  publicClient.readContract({ address: token, abi: ERC20_META_ABI, functionName: "name" }),
@@ -213,6 +205,22 @@ function randomAuthNonce() {
213
205
  globalThis.crypto.getRandomValues(bytes);
214
206
  return (0, import_viem3.bytesToHex)(bytes);
215
207
  }
208
+ function buildPermitTypedData(input) {
209
+ return {
210
+ domain: { name: input.tokenName, version: input.tokenVersion, chainId: input.chainId, verifyingContract: input.token },
211
+ types: {
212
+ Permit: [
213
+ { name: "owner", type: "address" },
214
+ { name: "spender", type: "address" },
215
+ { name: "value", type: "uint256" },
216
+ { name: "nonce", type: "uint256" },
217
+ { name: "deadline", type: "uint256" }
218
+ ]
219
+ },
220
+ primaryType: "Permit",
221
+ message: input.message
222
+ };
223
+ }
216
224
  var import_viem3, ERC20_META_ABI;
217
225
  var init_transfer_auth = __esm({
218
226
  "src/lib/transfer-auth.ts"() {
@@ -226,13 +234,15 @@ var init_transfer_auth = __esm({
226
234
  });
227
235
 
228
236
  // src/agents/surfliquid/surfliquid.constants.ts
229
- var SURFLIQUID_CHAIN_ID, SURFLIQUID_CHAIN_NAME, SURFLIQUID_USDC_ADDRESS, SURFLIQUID_MIN_DEPOSIT, SURFLIQUID_SUPPORTED_ASSETS, SURFLIQUID_ACTION_MAP;
237
+ var SURFLIQUID_CHAIN_ID, SURFLIQUID_CHAIN_NAME, SURFLIQUID_USDC_ADDRESS, SURFLIQUID_PERMIT_CAP, SURFLIQUID_PERMIT_TTL_SECONDS, SURFLIQUID_MIN_DEPOSIT, SURFLIQUID_SUPPORTED_ASSETS, SURFLIQUID_ACTION_MAP;
230
238
  var init_surfliquid_constants = __esm({
231
239
  "src/agents/surfliquid/surfliquid.constants.ts"() {
232
240
  "use strict";
233
241
  SURFLIQUID_CHAIN_ID = 8453;
234
242
  SURFLIQUID_CHAIN_NAME = "BASE";
235
243
  SURFLIQUID_USDC_ADDRESS = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
244
+ SURFLIQUID_PERMIT_CAP = 10000000000n;
245
+ SURFLIQUID_PERMIT_TTL_SECONDS = 3600n;
236
246
  SURFLIQUID_MIN_DEPOSIT = "0";
237
247
  SURFLIQUID_SUPPORTED_ASSETS = [
238
248
  {
@@ -645,20 +655,23 @@ var init_surfliquid_contracts = __esm({
645
655
  USDC_ABI = (0, import_viem6.parseAbi)([
646
656
  "function approve(address spender, uint256 amount)",
647
657
  "function transfer(address to, uint256 amount)",
658
+ "function transferFrom(address from, address to, uint256 value)",
648
659
  "function balanceOf(address account) view returns (uint256)",
649
- "function receiveWithAuthorization(address from, address to, uint256 value, uint256 validAfter, uint256 validBefore, bytes32 nonce, bytes signature)"
660
+ "function allowance(address owner, address spender) view returns (uint256)",
661
+ "function nonces(address owner) view returns (uint256)",
662
+ "function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)"
650
663
  ]);
651
664
  }
652
665
  });
653
666
 
654
667
  // src/agents/surfliquid/surfliquid.calls.ts
655
668
  function buildDepositCalls(input) {
656
- const { smartAccount, vault, amount, authorization, deploySalt } = input;
657
- if (authorization.to.toLowerCase() !== smartAccount.toLowerCase()) {
658
- throw new Error("Transfer authorization must pay the smart account");
669
+ const { smartAccount, owner, vault, amount, permit, deploySalt } = input;
670
+ if (permit && permit.owner.toLowerCase() !== owner.toLowerCase()) {
671
+ throw new Error("Permit must be signed by the smart account's owner");
659
672
  }
660
- if (authorization.value < amount) {
661
- throw new Error("Transfer authorization is worth less than the deposit");
673
+ if (permit && permit.value < amount) {
674
+ throw new Error("Permit allowance is worth less than the deposit");
662
675
  }
663
676
  if (!input.hasInitialDeposit && !input.morphoVault) {
664
677
  throw new Error("A first deposit needs a target morpho vault");
@@ -672,16 +685,21 @@ function buildDepositCalls(input) {
672
685
  ])
673
686
  );
674
687
  }
688
+ if (permit) {
689
+ calls.push(
690
+ call(SURFLIQUID_USDC_ADDRESS, USDC_ABI, "permit", [
691
+ permit.owner,
692
+ smartAccount,
693
+ permit.value,
694
+ permit.deadline,
695
+ permit.v,
696
+ permit.r,
697
+ permit.s
698
+ ])
699
+ );
700
+ }
675
701
  calls.push(
676
- call(SURFLIQUID_USDC_ADDRESS, USDC_ABI, "receiveWithAuthorization", [
677
- authorization.from,
678
- authorization.to,
679
- authorization.value,
680
- authorization.validAfter,
681
- authorization.validBefore,
682
- authorization.nonce,
683
- authorization.signature
684
- ]),
702
+ call(SURFLIQUID_USDC_ADDRESS, USDC_ABI, "transferFrom", [owner, smartAccount, amount]),
685
703
  call(SURFLIQUID_USDC_ADDRESS, USDC_ABI, "approve", [vault, amount]),
686
704
  input.hasInitialDeposit ? call(vault, SURFLIQUID_VAULT_ABI, "userDeposit", [SURFLIQUID_USDC_ADDRESS, amount]) : call(vault, SURFLIQUID_VAULT_ABI, "initialDeposit", [
687
705
  SURFLIQUID_USDC_ADDRESS,
@@ -751,22 +769,23 @@ async function pickMorphoVault(api) {
751
769
  }
752
770
  return candidate.vaultAddress;
753
771
  }
754
- async function depositSponsored(input) {
755
- const { api, chain, wallet, amount } = input;
756
- const { vault, deploySalt, registerAfterDeposit } = await resolveVault(input);
757
- const hasInitialDeposit = deploySalt ? false : await chain.hasInitialDeposit(vault, SURFLIQUID_USDC_ADDRESS);
758
- const morphoVault = hasInitialDeposit ? void 0 : await pickMorphoVault(api);
759
- const { tokenName, tokenVersion } = await chain.readTokenMeta();
772
+ async function permitIfShort(input) {
773
+ const { chain, wallet, amount } = input;
774
+ const allowance = await chain.readAllowance(wallet.ownerAddress, wallet.smartAccountAddress);
775
+ if (allowance >= amount) return void 0;
776
+ const [{ tokenName, tokenVersion }, nonce] = await Promise.all([
777
+ chain.readTokenMeta(),
778
+ chain.readPermitNonce(wallet.ownerAddress)
779
+ ]);
760
780
  const message = {
761
- from: wallet.ownerAddress,
762
- to: wallet.smartAccountAddress,
763
- value: amount,
764
- validAfter: 0n,
765
- validBefore: BigInt(Math.floor(Date.now() / 1e3)) + AUTHORIZATION_TTL_SECONDS,
766
- nonce: randomAuthNonce()
781
+ owner: wallet.ownerAddress,
782
+ spender: wallet.smartAccountAddress,
783
+ value: amount > SURFLIQUID_PERMIT_CAP ? amount : SURFLIQUID_PERMIT_CAP,
784
+ nonce,
785
+ deadline: BigInt(Math.floor(Date.now() / 1e3)) + SURFLIQUID_PERMIT_TTL_SECONDS
767
786
  };
768
- const signature = await wallet.signTransferAuthorization(
769
- buildReceiveWithAuthorizationTypedData({
787
+ const signature = await wallet.signPermit(
788
+ buildPermitTypedData({
770
789
  token: SURFLIQUID_USDC_ADDRESS,
771
790
  chainId: SURFLIQUID_CHAIN_ID,
772
791
  tokenName,
@@ -774,12 +793,40 @@ async function depositSponsored(input) {
774
793
  message
775
794
  })
776
795
  );
796
+ const { r, s, v, yParity } = (0, import_viem8.parseSignature)(signature);
797
+ return {
798
+ owner: message.owner,
799
+ value: message.value,
800
+ deadline: message.deadline,
801
+ v: Number(v ?? BigInt(yParity + 27)),
802
+ r,
803
+ s
804
+ };
805
+ }
806
+ async function readStuckBalance(input) {
807
+ return input.chain.usdcBalanceOf(input.wallet.smartAccountAddress);
808
+ }
809
+ async function sweepStuckBalance(input) {
810
+ const stranded = await readStuckBalance(input);
811
+ if (stranded === 0n) return { amount: 0n };
812
+ const txHash = await input.wallet.sendCalls(
813
+ buildSweepCalls({ owner: input.wallet.ownerAddress, amount: stranded })
814
+ );
815
+ return { txHash, amount: stranded };
816
+ }
817
+ async function depositSponsored(input) {
818
+ const { api, chain, wallet, amount } = input;
819
+ const { vault, deploySalt, registerAfterDeposit } = await resolveVault(input);
820
+ const hasInitialDeposit = deploySalt ? false : await chain.hasInitialDeposit(vault, SURFLIQUID_USDC_ADDRESS);
821
+ const morphoVault = hasInitialDeposit ? void 0 : await pickMorphoVault(api);
822
+ const permit = await permitIfShort({ chain, wallet, amount });
777
823
  const txHash = await wallet.sendCalls(
778
824
  buildDepositCalls({
779
825
  smartAccount: wallet.smartAccountAddress,
826
+ owner: wallet.ownerAddress,
780
827
  vault,
781
828
  amount,
782
- authorization: { ...message, signature },
829
+ permit,
783
830
  hasInitialDeposit,
784
831
  morphoVault,
785
832
  deploySalt
@@ -813,7 +860,15 @@ async function withdrawSponsored(input) {
813
860
  if (owner.toLowerCase() !== wallet.smartAccountAddress.toLowerCase()) {
814
861
  throw new VaultNotSponsorableError(`SurfLiquid vault ${vault} is not owned by the smart account`);
815
862
  }
816
- const withdrawHash = await wallet.sendCalls(buildWithdrawCalls({ vault, amount }));
863
+ let withdrawHash;
864
+ try {
865
+ withdrawHash = await wallet.sendCalls(buildWithdrawCalls({ vault, amount }));
866
+ } catch (redeemError) {
867
+ const stranded = await chain.usdcBalanceOf(wallet.smartAccountAddress);
868
+ if (stranded === 0n) throw redeemError;
869
+ const sweepHash = await wallet.sendCalls(buildSweepCalls({ owner: wallet.ownerAddress, amount: stranded }));
870
+ return { txHash: sweepHash, amount: stranded.toString() };
871
+ }
817
872
  try {
818
873
  const proceeds = await chain.usdcBalanceOf(wallet.smartAccountAddress);
819
874
  if (proceeds === 0n) return { txHash: withdrawHash, amount: "0" };
@@ -827,14 +882,14 @@ async function withdrawSponsored(input) {
827
882
  );
828
883
  }
829
884
  }
830
- var AUTHORIZATION_TTL_SECONDS, SubmittedError, VaultNotSponsorableError;
885
+ var import_viem8, SubmittedError, VaultNotSponsorableError;
831
886
  var init_surfliquid_sponsorship = __esm({
832
887
  "src/agents/surfliquid/surfliquid.sponsorship.ts"() {
833
888
  "use strict";
889
+ import_viem8 = require("viem");
834
890
  init_transfer_auth();
835
891
  init_surfliquid_constants();
836
892
  init_surfliquid_calls();
837
- AUTHORIZATION_TTL_SECONDS = 3600n;
838
893
  SubmittedError = class extends Error {
839
894
  constructor(message, userOpHash) {
840
895
  super(message);
@@ -946,7 +1001,7 @@ __export(surfliquid_smart_account_exports, {
946
1001
  pinAccount: () => pinAccount
947
1002
  });
948
1003
  function publicClientFor(rpcUrl) {
949
- return (0, import_viem8.createPublicClient)({ chain: import_chains2.base, transport: (0, import_viem8.http)(rpcUrl) });
1004
+ return (0, import_viem9.createPublicClient)({ chain: import_chains2.base, transport: (0, import_viem9.http)(rpcUrl) });
950
1005
  }
951
1006
  function createSponsoredChain(rpcUrl) {
952
1007
  const client = publicClientFor(rpcUrl);
@@ -976,7 +1031,19 @@ function createSponsoredChain(rpcUrl) {
976
1031
  }),
977
1032
  // Cast: viem's OP-stack tx union does not match the generic PublicClient
978
1033
  // the helper is typed against, though every method it uses is present.
979
- readTokenMeta: () => readTokenMeta(client, SURFLIQUID_USDC_ADDRESS)
1034
+ readTokenMeta: () => readTokenMeta(client, SURFLIQUID_USDC_ADDRESS),
1035
+ readAllowance: (owner, spender) => client.readContract({
1036
+ address: SURFLIQUID_USDC_ADDRESS,
1037
+ abi: USDC_ABI,
1038
+ functionName: "allowance",
1039
+ args: [owner, spender]
1040
+ }),
1041
+ readPermitNonce: (owner) => client.readContract({
1042
+ address: SURFLIQUID_USDC_ADDRESS,
1043
+ abi: USDC_ABI,
1044
+ functionName: "nonces",
1045
+ args: [owner]
1046
+ })
980
1047
  };
981
1048
  }
982
1049
  function pinAccount(provider, address) {
@@ -992,7 +1059,7 @@ async function createSponsoredWallet(input) {
992
1059
  owner: pinAccount(input.provider, input.ownerAddress),
993
1060
  entryPoint
994
1061
  });
995
- const bundlerTransport = (0, import_viem8.http)(sponsorProxyUrl(input.routingApiBaseUrl), {
1062
+ const bundlerTransport = (0, import_viem9.http)(sponsorProxyUrl(input.routingApiBaseUrl), {
996
1063
  fetchOptions: { headers: { "x-owney-api-key": input.apiKey } }
997
1064
  });
998
1065
  const pimlico = (0, import_pimlico.createPimlicoClient)({ transport: bundlerTransport, entryPoint });
@@ -1005,16 +1072,16 @@ async function createSponsoredWallet(input) {
1005
1072
  estimateFeesPerGas: async () => (await pimlico.getUserOperationGasPrice()).fast
1006
1073
  }
1007
1074
  });
1008
- const walletClient = (0, import_viem8.createWalletClient)({
1075
+ const walletClient = (0, import_viem9.createWalletClient)({
1009
1076
  account: input.ownerAddress,
1010
1077
  chain: import_chains2.base,
1011
- transport: (0, import_viem8.custom)(input.provider)
1078
+ transport: (0, import_viem9.custom)(input.provider)
1012
1079
  });
1013
1080
  return {
1014
1081
  smartAccountAddress: account.address,
1015
1082
  ownerAddress: input.ownerAddress,
1016
1083
  // The EOA signs, not the smart account: USDC verifies ECDSA from the token holder.
1017
- signTransferAuthorization: (typedData) => walletClient.signTypedData({
1084
+ signPermit: (typedData) => walletClient.signTypedData({
1018
1085
  account: input.ownerAddress,
1019
1086
  domain: typedData.domain,
1020
1087
  types: typedData.types,
@@ -1037,14 +1104,14 @@ async function createSponsoredWallet(input) {
1037
1104
  }
1038
1105
  };
1039
1106
  }
1040
- var import_permissionless, import_accounts, import_pimlico, import_viem8, import_account_abstraction, import_chains2, sponsorProxyUrl;
1107
+ var import_permissionless, import_accounts, import_pimlico, import_viem9, import_account_abstraction, import_chains2, sponsorProxyUrl;
1041
1108
  var init_surfliquid_smart_account = __esm({
1042
1109
  "src/agents/surfliquid/surfliquid.smart-account.ts"() {
1043
1110
  "use strict";
1044
1111
  import_permissionless = require("permissionless");
1045
1112
  import_accounts = require("permissionless/accounts");
1046
1113
  import_pimlico = require("permissionless/clients/pimlico");
1047
- import_viem8 = require("viem");
1114
+ import_viem9 = require("viem");
1048
1115
  import_account_abstraction = require("viem/account-abstraction");
1049
1116
  import_chains2 = require("viem/chains");
1050
1117
  init_transfer_auth();
@@ -1075,11 +1142,11 @@ function toOwneyError(error) {
1075
1142
  }
1076
1143
  return new OwneyError("SPONSORSHIP_UNAVAILABLE", message, void 0, AGENT_ID2);
1077
1144
  }
1078
- var import_viem9, import_chains3, AGENT_ID2, WALLET_REJECTED_CODE, DISCOVERY_WALLET2, HISTORY_DEFAULT_LIMIT, APY_WINDOW_KEY2, SurfLiquidAgent;
1145
+ var import_viem10, import_chains3, AGENT_ID2, WALLET_REJECTED_CODE, DISCOVERY_WALLET2, HISTORY_DEFAULT_LIMIT, APY_WINDOW_KEY2, SurfLiquidAgent;
1079
1146
  var init_surfliquid_agent = __esm({
1080
1147
  "src/agents/surfliquid/surfliquid.agent.ts"() {
1081
1148
  "use strict";
1082
- import_viem9 = require("viem");
1149
+ import_viem10 = require("viem");
1083
1150
  import_chains3 = require("viem/chains");
1084
1151
  init_errors();
1085
1152
  init_surfliquid_constants();
@@ -1133,10 +1200,10 @@ var init_surfliquid_agent = __esm({
1133
1200
  if (this.connectPromise) return this.connectPromise;
1134
1201
  this.connectPromise = (async () => {
1135
1202
  const message = await broker.nonce();
1136
- const walletClient = (0, import_viem9.createWalletClient)({
1203
+ const walletClient = (0, import_viem10.createWalletClient)({
1137
1204
  account: state.walletAddress,
1138
1205
  chain: import_chains3.base,
1139
- transport: (0, import_viem9.custom)(state.provider)
1206
+ transport: (0, import_viem10.custom)(state.provider)
1140
1207
  });
1141
1208
  const signature = await walletClient.signMessage({ account: state.walletAddress, message });
1142
1209
  await broker.login(message, signature);
@@ -1218,6 +1285,24 @@ var init_surfliquid_agent = __esm({
1218
1285
  throw toOwneyError(error);
1219
1286
  }
1220
1287
  }
1288
+ /** Funds a prior withdrawal's sweep left in the smart account (never reached the EOA). No session needed — pure read. */
1289
+ async getStuckBalance(state) {
1290
+ const wallet = await this.sponsoredWallet(state);
1291
+ const { createSponsoredChain: createSponsoredChain2 } = await Promise.resolve().then(() => (init_surfliquid_smart_account(), surfliquid_smart_account_exports));
1292
+ const amount = await readStuckBalance({ chain: createSponsoredChain2(this.config.rpcUrl), wallet });
1293
+ return { amount: amount.toString(), smartAccountAddress: wallet.smartAccountAddress };
1294
+ }
1295
+ /** Sweep the stranded balance to the owner's EOA — one sponsored userOp, one signature. */
1296
+ async recoverStuckBalance(state) {
1297
+ const wallet = await this.sponsoredWallet(state);
1298
+ const { createSponsoredChain: createSponsoredChain2 } = await Promise.resolve().then(() => (init_surfliquid_smart_account(), surfliquid_smart_account_exports));
1299
+ try {
1300
+ const { txHash, amount } = await sweepStuckBalance({ chain: createSponsoredChain2(this.config.rpcUrl), wallet });
1301
+ return { txHash, type: "full", amount: amount.toString() };
1302
+ } catch (error) {
1303
+ throw toOwneyError(error);
1304
+ }
1305
+ }
1221
1306
  // --- IAgent: portfolio reads ---
1222
1307
  async vault(state) {
1223
1308
  const broker = await this.connect(state);
@@ -3481,7 +3566,7 @@ function aggregateApyByChainAndAsset(agentApys, agentBalances) {
3481
3566
  }
3482
3567
 
3483
3568
  // src/client.ts
3484
- var import_viem10 = require("viem");
3569
+ var import_viem11 = require("viem");
3485
3570
  var import_chains4 = require("viem/chains");
3486
3571
 
3487
3572
  // src/lib/sponsored-deposit.ts
@@ -4160,14 +4245,14 @@ var OwneySDK = class {
4160
4245
  // Casts work around viem's chain-narrowed Client vs the generic
4161
4246
  // PublicClient/WalletClient param types — structurally identical at
4162
4247
  // runtime, but the two share a name TS treats as unrelated.
4163
- getPublicClient: (cid) => (0, import_viem10.createPublicClient)({
4248
+ getPublicClient: (cid) => (0, import_viem11.createPublicClient)({
4164
4249
  chain: VIEM_CHAIN2[cid],
4165
- transport: (0, import_viem10.custom)(provider)
4250
+ transport: (0, import_viem11.custom)(provider)
4166
4251
  }),
4167
- getWalletClient: (cid) => (0, import_viem10.createWalletClient)({
4252
+ getWalletClient: (cid) => (0, import_viem11.createWalletClient)({
4168
4253
  account: owner,
4169
4254
  chain: VIEM_CHAIN2[cid],
4170
- transport: (0, import_viem10.custom)(provider)
4255
+ transport: (0, import_viem11.custom)(provider)
4171
4256
  })
4172
4257
  });
4173
4258
  if (!onApproved) this.cachedSponsoredCallback = callback;
@@ -4213,14 +4298,14 @@ var OwneySDK = class {
4213
4298
  // Casts work around viem's chain-narrowed Client vs the generic
4214
4299
  // PublicClient/WalletClient param types — structurally identical at
4215
4300
  // runtime, but the two share a name TS treats as unrelated.
4216
- getPublicClient: (cid) => (0, import_viem10.createPublicClient)({
4301
+ getPublicClient: (cid) => (0, import_viem11.createPublicClient)({
4217
4302
  chain: VIEM_CHAIN2[cid],
4218
- transport: (0, import_viem10.custom)(provider)
4303
+ transport: (0, import_viem11.custom)(provider)
4219
4304
  }),
4220
- getWalletClient: (cid) => (0, import_viem10.createWalletClient)({
4305
+ getWalletClient: (cid) => (0, import_viem11.createWalletClient)({
4221
4306
  account: owner,
4222
4307
  chain: VIEM_CHAIN2[cid],
4223
- transport: (0, import_viem10.custom)(provider)
4308
+ transport: (0, import_viem11.custom)(provider)
4224
4309
  })
4225
4310
  });
4226
4311
  if (!onApproved) this.cachedWethSponsoredCallback = callback;
@@ -4979,6 +5064,31 @@ var OwneySDK = class {
4979
5064
  }
4980
5065
  return { agentResult: results, totalWithdrawn: withdrawn.toString() };
4981
5066
  }
5067
+ /**
5068
+ * Funds a prior withdrawal left stranded in the agent's smart account (the
5069
+ * payout leg never reached the owner's EOA). Read-only — check once after
5070
+ * connect. Agents without a smart account model report "0".
5071
+ */
5072
+ async getStuckBalance(agentId) {
5073
+ const state = this.requireState();
5074
+ const chainId = this.requireChainId();
5075
+ const agent = this.getAgent(agentId);
5076
+ if (!agent.getStuckBalance) return { amount: "0", smartAccountAddress: "" };
5077
+ return agent.getStuckBalance(state, chainId);
5078
+ }
5079
+ /** Sweep that stranded balance to the owner's EOA — one signature. No-op ("0") when nothing is stuck. */
5080
+ async recoverStuckBalance(agentId) {
5081
+ const state = this.requireState();
5082
+ const chainId = this.requireChainId();
5083
+ const agent = this.getAgent(agentId);
5084
+ if (!agent.recoverStuckBalance) return { type: "full", amount: "0" };
5085
+ return withFailureReporting(
5086
+ this.apiKey,
5087
+ agent.id,
5088
+ () => agent.recoverStuckBalance(state, chainId),
5089
+ this.routingApiBaseUrl
5090
+ );
5091
+ }
4982
5092
  // --- Portfolio reads ---
4983
5093
  /**
4984
5094
  * Get the user's balances for a specific agent, or aggregated across all agents.
@@ -5314,10 +5424,10 @@ var OwneySDK = class {
5314
5424
  );
5315
5425
  }
5316
5426
  const provider = this.requireConnectedProvider();
5317
- const wallet = (0, import_viem10.createWalletClient)({
5427
+ const wallet = (0, import_viem11.createWalletClient)({
5318
5428
  account: state.walletAddress,
5319
5429
  chain: VIEM_CHAIN2[chainId],
5320
- transport: (0, import_viem10.custom)(provider)
5430
+ transport: (0, import_viem11.custom)(provider)
5321
5431
  });
5322
5432
  const hash = await wallet.writeContract({
5323
5433
  address: token,
@@ -5327,9 +5437,9 @@ var OwneySDK = class {
5327
5437
  account: state.walletAddress,
5328
5438
  chain: VIEM_CHAIN2[chainId]
5329
5439
  });
5330
- const publicClient = (0, import_viem10.createPublicClient)({
5440
+ const publicClient = (0, import_viem11.createPublicClient)({
5331
5441
  chain: VIEM_CHAIN2[chainId],
5332
- transport: (0, import_viem10.custom)(provider)
5442
+ transport: (0, import_viem11.custom)(provider)
5333
5443
  });
5334
5444
  const receipt = await publicClient.waitForTransactionReceipt({
5335
5445
  hash,
@@ -5445,7 +5555,7 @@ init_errors();
5445
5555
  init_debug();
5446
5556
 
5447
5557
  // src/agents/zyfai/zyfai.siwx.ts
5448
- var import_viem11 = require("viem");
5558
+ var import_viem12 = require("viem");
5449
5559
  var import_siwe = require("siwe");
5450
5560
  var import_sdk2 = require("@zyfai/sdk");
5451
5561
 
@@ -5572,7 +5682,7 @@ function buildSIWXConfig(deps) {
5572
5682
  issuedAt,
5573
5683
  toString() {
5574
5684
  return new import_siwe.SiweMessage({
5575
- address: (0, import_viem11.getAddress)(accountAddress),
5685
+ address: (0, import_viem12.getAddress)(accountAddress),
5576
5686
  chainId: numericChainId(chainId),
5577
5687
  domain,
5578
5688
  uri,
package/dist/index.d.cts CHANGED
@@ -195,6 +195,13 @@ interface AgentWithdrawResult {
195
195
  /** Smallest-unit amount, or a provider sentinel such as "all" for a full request. */
196
196
  amount: string;
197
197
  }
198
+ /** Funds a prior withdrawal left in the agent's smart account, awaiting recovery to the owner's EOA. */
199
+ interface AgentStuckBalance {
200
+ /** Smallest-unit amount stuck in the smart account; "0" when nothing is stuck. */
201
+ amount: string;
202
+ /** The smart account holding the funds (for display / on-chain verification). */
203
+ smartAccountAddress: string;
204
+ }
198
205
  interface OwneyWithdrawResult {
199
206
  agentResult: Record<AgentId, AgentWithdrawResult>;
200
207
  /**
@@ -446,6 +453,14 @@ interface IAgent {
446
453
  * a write occurred (`false` = already enabled / not supported).
447
454
  */
448
455
  ensureAutoSelectProtocols?(state: ConnectionState, chainId: number, asset: "USDC" | "WETH"): Promise<boolean>;
456
+ /**
457
+ * Read funds a prior withdrawal left stranded in the agent's smart account
458
+ * (the payout leg never reached the owner's EOA). Optional capability — only
459
+ * agents with a per-user smart account model this. Checked once after connect.
460
+ */
461
+ getStuckBalance?(state: ConnectionState, chainId: number): Promise<AgentStuckBalance>;
462
+ /** Sweep that stranded balance to the owner's EOA. No-op (amount "0") when nothing is stuck. */
463
+ recoverStuckBalance?(state: ConnectionState, chainId: number): Promise<AgentWithdrawResult>;
449
464
  getAgentApy(days: DailyApyDays, options?: AgentApyOptions): Promise<AgentApy>;
450
465
  }
451
466
  /**
@@ -656,6 +671,14 @@ declare class OwneySDK {
656
671
  * @returns {AgentWithdrawResult} for a single agent, or {OwneyWithdrawResult} with per-agent results
657
672
  */
658
673
  withdraw(options: WithdrawOptions): Promise<OwneyWithdrawResult | AgentWithdrawResult>;
674
+ /**
675
+ * Funds a prior withdrawal left stranded in the agent's smart account (the
676
+ * payout leg never reached the owner's EOA). Read-only — check once after
677
+ * connect. Agents without a smart account model report "0".
678
+ */
679
+ getStuckBalance(agentId: AgentId): Promise<AgentStuckBalance>;
680
+ /** Sweep that stranded balance to the owner's EOA — one signature. No-op ("0") when nothing is stuck. */
681
+ recoverStuckBalance(agentId: AgentId): Promise<AgentWithdrawResult>;
659
682
  /**
660
683
  * Get the user's balances for a specific agent, or aggregated across all agents.
661
684
  * @param agentId - Optional. Agent to query. Omit for aggregated balances.
@@ -812,4 +835,4 @@ type OwneySIWXConfig = {
812
835
  */
813
836
  declare function createOwneySIWX(config: OwneySIWXConfig): SIWXConfig;
814
837
 
815
- export { type AccountAgentApy, type AccountApyOptions, type AgentApy, type AgentApyDetails, type AgentBalance, AgentChainIncompatibleError, type AgentEarnings, type AgentHistoryEntry, type AgentHistoryPosition, type AgentId, AgentNotFoundError, type AgentSupportedAsset, type AgentSupportedAssets, type AgentUserProfile, type AgentWithdrawResult, type AgentsApyOptions, type AllocationAgentApy, type AllocationApyOptions, type ApyByChainAndAsset, type ApyHistoryPoint, type Asset, type AvailableAgent, type AvailableAgentsOptions, type ConnectionState, type DailyApyDays, type DepositCallback, type DepositOptions, type HistoryAction, type HistoryFilters, type HistoryOptions, type HistoryTransaction, type IAgent, InvalidHistoryCursorError, NotConnectedError, type OwneyAccountApy, type OwneyAgentApy, type OwneyAgentHistory, type OwneyAllocationApy, type OwneyBalances, type OwneyDepositResult, type OwneyEarnings, OwneyError, type OwneyErrorCode, type OwneyMultiDepositResult, type OwneyPosition, OwneySDK, type OwneySDKConfig, type OwneySIWXConfig, type OwneySupportedChainId, type OwneySupportedChains, type OwneySupportedTokens, type OwneyToken, type OwneyUserProfile, type OwneyWithdrawResult, type RebalanceLog, type WithdrawOptions, createOwneySIWX, setOwneyDebug };
838
+ export { type AccountAgentApy, type AccountApyOptions, type AgentApy, type AgentApyDetails, type AgentBalance, AgentChainIncompatibleError, type AgentEarnings, type AgentHistoryEntry, type AgentHistoryPosition, type AgentId, AgentNotFoundError, type AgentStuckBalance, type AgentSupportedAsset, type AgentSupportedAssets, type AgentUserProfile, type AgentWithdrawResult, type AgentsApyOptions, type AllocationAgentApy, type AllocationApyOptions, type ApyByChainAndAsset, type ApyHistoryPoint, type Asset, type AvailableAgent, type AvailableAgentsOptions, type ConnectionState, type DailyApyDays, type DepositCallback, type DepositOptions, type HistoryAction, type HistoryFilters, type HistoryOptions, type HistoryTransaction, type IAgent, InvalidHistoryCursorError, NotConnectedError, type OwneyAccountApy, type OwneyAgentApy, type OwneyAgentHistory, type OwneyAllocationApy, type OwneyBalances, type OwneyDepositResult, type OwneyEarnings, OwneyError, type OwneyErrorCode, type OwneyMultiDepositResult, type OwneyPosition, OwneySDK, type OwneySDKConfig, type OwneySIWXConfig, type OwneySupportedChainId, type OwneySupportedChains, type OwneySupportedTokens, type OwneyToken, type OwneyUserProfile, type OwneyWithdrawResult, type RebalanceLog, type WithdrawOptions, createOwneySIWX, setOwneyDebug };
package/dist/index.d.ts CHANGED
@@ -195,6 +195,13 @@ interface AgentWithdrawResult {
195
195
  /** Smallest-unit amount, or a provider sentinel such as "all" for a full request. */
196
196
  amount: string;
197
197
  }
198
+ /** Funds a prior withdrawal left in the agent's smart account, awaiting recovery to the owner's EOA. */
199
+ interface AgentStuckBalance {
200
+ /** Smallest-unit amount stuck in the smart account; "0" when nothing is stuck. */
201
+ amount: string;
202
+ /** The smart account holding the funds (for display / on-chain verification). */
203
+ smartAccountAddress: string;
204
+ }
198
205
  interface OwneyWithdrawResult {
199
206
  agentResult: Record<AgentId, AgentWithdrawResult>;
200
207
  /**
@@ -446,6 +453,14 @@ interface IAgent {
446
453
  * a write occurred (`false` = already enabled / not supported).
447
454
  */
448
455
  ensureAutoSelectProtocols?(state: ConnectionState, chainId: number, asset: "USDC" | "WETH"): Promise<boolean>;
456
+ /**
457
+ * Read funds a prior withdrawal left stranded in the agent's smart account
458
+ * (the payout leg never reached the owner's EOA). Optional capability — only
459
+ * agents with a per-user smart account model this. Checked once after connect.
460
+ */
461
+ getStuckBalance?(state: ConnectionState, chainId: number): Promise<AgentStuckBalance>;
462
+ /** Sweep that stranded balance to the owner's EOA. No-op (amount "0") when nothing is stuck. */
463
+ recoverStuckBalance?(state: ConnectionState, chainId: number): Promise<AgentWithdrawResult>;
449
464
  getAgentApy(days: DailyApyDays, options?: AgentApyOptions): Promise<AgentApy>;
450
465
  }
451
466
  /**
@@ -656,6 +671,14 @@ declare class OwneySDK {
656
671
  * @returns {AgentWithdrawResult} for a single agent, or {OwneyWithdrawResult} with per-agent results
657
672
  */
658
673
  withdraw(options: WithdrawOptions): Promise<OwneyWithdrawResult | AgentWithdrawResult>;
674
+ /**
675
+ * Funds a prior withdrawal left stranded in the agent's smart account (the
676
+ * payout leg never reached the owner's EOA). Read-only — check once after
677
+ * connect. Agents without a smart account model report "0".
678
+ */
679
+ getStuckBalance(agentId: AgentId): Promise<AgentStuckBalance>;
680
+ /** Sweep that stranded balance to the owner's EOA — one signature. No-op ("0") when nothing is stuck. */
681
+ recoverStuckBalance(agentId: AgentId): Promise<AgentWithdrawResult>;
659
682
  /**
660
683
  * Get the user's balances for a specific agent, or aggregated across all agents.
661
684
  * @param agentId - Optional. Agent to query. Omit for aggregated balances.
@@ -812,4 +835,4 @@ type OwneySIWXConfig = {
812
835
  */
813
836
  declare function createOwneySIWX(config: OwneySIWXConfig): SIWXConfig;
814
837
 
815
- export { type AccountAgentApy, type AccountApyOptions, type AgentApy, type AgentApyDetails, type AgentBalance, AgentChainIncompatibleError, type AgentEarnings, type AgentHistoryEntry, type AgentHistoryPosition, type AgentId, AgentNotFoundError, type AgentSupportedAsset, type AgentSupportedAssets, type AgentUserProfile, type AgentWithdrawResult, type AgentsApyOptions, type AllocationAgentApy, type AllocationApyOptions, type ApyByChainAndAsset, type ApyHistoryPoint, type Asset, type AvailableAgent, type AvailableAgentsOptions, type ConnectionState, type DailyApyDays, type DepositCallback, type DepositOptions, type HistoryAction, type HistoryFilters, type HistoryOptions, type HistoryTransaction, type IAgent, InvalidHistoryCursorError, NotConnectedError, type OwneyAccountApy, type OwneyAgentApy, type OwneyAgentHistory, type OwneyAllocationApy, type OwneyBalances, type OwneyDepositResult, type OwneyEarnings, OwneyError, type OwneyErrorCode, type OwneyMultiDepositResult, type OwneyPosition, OwneySDK, type OwneySDKConfig, type OwneySIWXConfig, type OwneySupportedChainId, type OwneySupportedChains, type OwneySupportedTokens, type OwneyToken, type OwneyUserProfile, type OwneyWithdrawResult, type RebalanceLog, type WithdrawOptions, createOwneySIWX, setOwneyDebug };
838
+ export { type AccountAgentApy, type AccountApyOptions, type AgentApy, type AgentApyDetails, type AgentBalance, AgentChainIncompatibleError, type AgentEarnings, type AgentHistoryEntry, type AgentHistoryPosition, type AgentId, AgentNotFoundError, type AgentStuckBalance, type AgentSupportedAsset, type AgentSupportedAssets, type AgentUserProfile, type AgentWithdrawResult, type AgentsApyOptions, type AllocationAgentApy, type AllocationApyOptions, type ApyByChainAndAsset, type ApyHistoryPoint, type Asset, type AvailableAgent, type AvailableAgentsOptions, type ConnectionState, type DailyApyDays, type DepositCallback, type DepositOptions, type HistoryAction, type HistoryFilters, type HistoryOptions, type HistoryTransaction, type IAgent, InvalidHistoryCursorError, NotConnectedError, type OwneyAccountApy, type OwneyAgentApy, type OwneyAgentHistory, type OwneyAllocationApy, type OwneyBalances, type OwneyDepositResult, type OwneyEarnings, OwneyError, type OwneyErrorCode, type OwneyMultiDepositResult, type OwneyPosition, OwneySDK, type OwneySDKConfig, type OwneySIWXConfig, type OwneySupportedChainId, type OwneySupportedChains, type OwneySupportedTokens, type OwneyToken, type OwneyUserProfile, type OwneyWithdrawResult, type RebalanceLog, type WithdrawOptions, createOwneySIWX, setOwneyDebug };
package/dist/index.js CHANGED
@@ -12,7 +12,7 @@ import {
12
12
  buildTransferWithAuthorizationTypedData,
13
13
  randomAuthNonce,
14
14
  readTokenMeta
15
- } from "./chunk-5LU2SHO7.js";
15
+ } from "./chunk-AURO3C3R.js";
16
16
 
17
17
  // src/lib/rate-limit.ts
18
18
  function rateLimitDelay(error, now = Date.now()) {
@@ -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-XDJ672GM.js");
3039
+ const { SurfLiquidAgent } = await import("./surfliquid.agent-E54CPWXF.js");
3040
3040
  return new SurfLiquidAgent({
3041
3041
  apiKey: this.apiKey,
3042
3042
  routingApiBaseUrl: this.routingApiBaseUrl
@@ -3691,6 +3691,31 @@ var OwneySDK = class {
3691
3691
  }
3692
3692
  return { agentResult: results, totalWithdrawn: withdrawn.toString() };
3693
3693
  }
3694
+ /**
3695
+ * Funds a prior withdrawal left stranded in the agent's smart account (the
3696
+ * payout leg never reached the owner's EOA). Read-only — check once after
3697
+ * connect. Agents without a smart account model report "0".
3698
+ */
3699
+ async getStuckBalance(agentId) {
3700
+ const state = this.requireState();
3701
+ const chainId = this.requireChainId();
3702
+ const agent = this.getAgent(agentId);
3703
+ if (!agent.getStuckBalance) return { amount: "0", smartAccountAddress: "" };
3704
+ return agent.getStuckBalance(state, chainId);
3705
+ }
3706
+ /** Sweep that stranded balance to the owner's EOA — one signature. No-op ("0") when nothing is stuck. */
3707
+ async recoverStuckBalance(agentId) {
3708
+ const state = this.requireState();
3709
+ const chainId = this.requireChainId();
3710
+ const agent = this.getAgent(agentId);
3711
+ if (!agent.recoverStuckBalance) return { type: "full", amount: "0" };
3712
+ return withFailureReporting(
3713
+ this.apiKey,
3714
+ agent.id,
3715
+ () => agent.recoverStuckBalance(state, chainId),
3716
+ this.routingApiBaseUrl
3717
+ );
3718
+ }
3694
3719
  // --- Portfolio reads ---
3695
3720
  /**
3696
3721
  * Get the user's balances for a specific agent, or aggregated across all agents.
@@ -10,9 +10,11 @@ import {
10
10
  SubmittedError,
11
11
  VaultNotSponsorableError,
12
12
  depositSponsored,
13
+ readStuckBalance,
14
+ sweepStuckBalance,
13
15
  withdrawSponsored
14
- } from "./chunk-W3FYRJLJ.js";
15
- import "./chunk-5LU2SHO7.js";
16
+ } from "./chunk-5W56YOBO.js";
17
+ import "./chunk-AURO3C3R.js";
16
18
 
17
19
  // src/agents/surfliquid/surfliquid.agent.ts
18
20
  import { createWalletClient, custom } from "viem";
@@ -533,7 +535,7 @@ var SurfLiquidAgent = class {
533
535
  }
534
536
  }
535
537
  async sponsoredWallet(state) {
536
- const { createSponsoredWallet } = await import("./surfliquid.smart-account-DWV5B3D5.js");
538
+ const { createSponsoredWallet } = await import("./surfliquid.smart-account-O6YPCQT3.js");
537
539
  return createSponsoredWallet({
538
540
  provider: state.provider,
539
541
  ownerAddress: state.walletAddress,
@@ -555,7 +557,7 @@ var SurfLiquidAgent = class {
555
557
  async deposit(state, _chainId, amount, _asset, _depositCallback) {
556
558
  const broker = await this.connect(state);
557
559
  const wallet = await this.sponsoredWallet(state);
558
- const { createSponsoredChain } = await import("./surfliquid.smart-account-DWV5B3D5.js");
560
+ const { createSponsoredChain } = await import("./surfliquid.smart-account-O6YPCQT3.js");
559
561
  try {
560
562
  const { txHash, vault } = await this.withSession(
561
563
  state,
@@ -570,7 +572,7 @@ var SurfLiquidAgent = class {
570
572
  async withdraw(state, _chainId, _token, amount) {
571
573
  const broker = await this.connect(state);
572
574
  const wallet = await this.sponsoredWallet(state);
573
- const { createSponsoredChain } = await import("./surfliquid.smart-account-DWV5B3D5.js");
575
+ const { createSponsoredChain } = await import("./surfliquid.smart-account-O6YPCQT3.js");
574
576
  try {
575
577
  const result = await this.withSession(
576
578
  state,
@@ -587,6 +589,24 @@ var SurfLiquidAgent = class {
587
589
  throw toOwneyError(error);
588
590
  }
589
591
  }
592
+ /** Funds a prior withdrawal's sweep left in the smart account (never reached the EOA). No session needed — pure read. */
593
+ async getStuckBalance(state) {
594
+ const wallet = await this.sponsoredWallet(state);
595
+ const { createSponsoredChain } = await import("./surfliquid.smart-account-O6YPCQT3.js");
596
+ const amount = await readStuckBalance({ chain: createSponsoredChain(this.config.rpcUrl), wallet });
597
+ return { amount: amount.toString(), smartAccountAddress: wallet.smartAccountAddress };
598
+ }
599
+ /** Sweep the stranded balance to the owner's EOA — one sponsored userOp, one signature. */
600
+ async recoverStuckBalance(state) {
601
+ const wallet = await this.sponsoredWallet(state);
602
+ const { createSponsoredChain } = await import("./surfliquid.smart-account-O6YPCQT3.js");
603
+ try {
604
+ const { txHash, amount } = await sweepStuckBalance({ chain: createSponsoredChain(this.config.rpcUrl), wallet });
605
+ return { txHash, type: "full", amount: amount.toString() };
606
+ } catch (error) {
607
+ throw toOwneyError(error);
608
+ }
609
+ }
590
610
  // --- IAgent: portfolio reads ---
591
611
  async vault(state) {
592
612
  const broker = await this.connect(state);
@@ -6,10 +6,10 @@ import {
6
6
  SURFLIQUID_VAULT_ABI,
7
7
  SubmittedError,
8
8
  USDC_ABI
9
- } from "./chunk-W3FYRJLJ.js";
9
+ } from "./chunk-5W56YOBO.js";
10
10
  import {
11
11
  readTokenMeta
12
- } from "./chunk-5LU2SHO7.js";
12
+ } from "./chunk-AURO3C3R.js";
13
13
 
14
14
  // src/agents/surfliquid/surfliquid.smart-account.ts
15
15
  import { createSmartAccountClient } from "permissionless";
@@ -55,7 +55,19 @@ function createSponsoredChain(rpcUrl) {
55
55
  }),
56
56
  // Cast: viem's OP-stack tx union does not match the generic PublicClient
57
57
  // the helper is typed against, though every method it uses is present.
58
- readTokenMeta: () => readTokenMeta(client, SURFLIQUID_USDC_ADDRESS)
58
+ readTokenMeta: () => readTokenMeta(client, SURFLIQUID_USDC_ADDRESS),
59
+ readAllowance: (owner, spender) => client.readContract({
60
+ address: SURFLIQUID_USDC_ADDRESS,
61
+ abi: USDC_ABI,
62
+ functionName: "allowance",
63
+ args: [owner, spender]
64
+ }),
65
+ readPermitNonce: (owner) => client.readContract({
66
+ address: SURFLIQUID_USDC_ADDRESS,
67
+ abi: USDC_ABI,
68
+ functionName: "nonces",
69
+ args: [owner]
70
+ })
59
71
  };
60
72
  }
61
73
  function pinAccount(provider, address) {
@@ -93,7 +105,7 @@ async function createSponsoredWallet(input) {
93
105
  smartAccountAddress: account.address,
94
106
  ownerAddress: input.ownerAddress,
95
107
  // The EOA signs, not the smart account: USDC verifies ECDSA from the token holder.
96
- signTransferAuthorization: (typedData) => walletClient.signTypedData({
108
+ signPermit: (typedData) => walletClient.signTypedData({
97
109
  account: input.ownerAddress,
98
110
  domain: typedData.domain,
99
111
  types: typedData.types,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@owney/sdk",
3
- "version": "0.7.22-beta.0",
3
+ "version": "0.7.22-beta.2",
4
4
  "type": "module",
5
5
  "main": "dist/index.cjs",
6
6
  "module": "dist/index.js",