@owney/sdk 0.6.9-beta.6 → 0.6.9-beta.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,140 @@
1
+ // src/errors.ts
2
+ var OwneyError = class extends Error {
3
+ code;
4
+ details;
5
+ agentId;
6
+ constructor(code, message, details, agentId) {
7
+ const prefix = agentId ? `[${code}][agent:${agentId}]` : `[${code}]`;
8
+ super(`${prefix} ${message}`);
9
+ this.name = "OwneyError";
10
+ this.code = code;
11
+ this.details = details;
12
+ this.agentId = agentId;
13
+ }
14
+ };
15
+ var AgentNotFoundError = class extends OwneyError {
16
+ constructor(agentId, available) {
17
+ super(
18
+ "AGENT_NOT_FOUND",
19
+ `Unknown agent "${agentId}". Available agents: ${available.join(", ")}`,
20
+ { agentId, available },
21
+ agentId
22
+ );
23
+ this.name = "AgentNotFoundError";
24
+ }
25
+ };
26
+ var NotConnectedError = class extends OwneyError {
27
+ constructor() {
28
+ super("NOT_CONNECTED", "Not connected. Call sdk.connect(provider) first.");
29
+ this.name = "NotConnectedError";
30
+ }
31
+ };
32
+ var AgentChainIncompatibleError = class extends OwneyError {
33
+ incompatibleAgents;
34
+ connectedChainId;
35
+ constructor(incompatibleAgents, connectedChainId) {
36
+ const details = incompatibleAgents.map(
37
+ ({ agentId, supportedChainIds }) => `"${agentId}" supports chains [${supportedChainIds.join(", ")}]`
38
+ ).join("; ");
39
+ super(
40
+ "AGENT_CHAIN_INCOMPATIBLE",
41
+ `Chain ${connectedChainId} is not supported by the following agents: ${details}`,
42
+ { incompatibleAgents, connectedChainId }
43
+ );
44
+ this.name = "AgentChainIncompatibleError";
45
+ this.incompatibleAgents = incompatibleAgents;
46
+ this.connectedChainId = connectedChainId;
47
+ }
48
+ };
49
+
50
+ // src/lib/permit2.ts
51
+ import { bytesToHex } from "viem";
52
+ var PERMIT2_ADDRESS = "0x000000000022D473030F116dDEE9F6B43aC78BA3";
53
+ var MAX_UINT256 = 2n ** 256n - 1n;
54
+ var ERC20_ALLOWANCE_ABI = [
55
+ {
56
+ type: "function",
57
+ name: "allowance",
58
+ stateMutability: "view",
59
+ inputs: [
60
+ { name: "owner", type: "address" },
61
+ { name: "spender", type: "address" }
62
+ ],
63
+ outputs: [{ name: "", type: "uint256" }]
64
+ },
65
+ {
66
+ type: "function",
67
+ name: "approve",
68
+ stateMutability: "nonpayable",
69
+ inputs: [
70
+ { name: "spender", type: "address" },
71
+ { name: "amount", type: "uint256" }
72
+ ],
73
+ outputs: [{ name: "", type: "bool" }]
74
+ },
75
+ {
76
+ type: "function",
77
+ name: "balanceOf",
78
+ stateMutability: "view",
79
+ inputs: [{ name: "account", type: "address" }],
80
+ outputs: [{ name: "", type: "uint256" }]
81
+ }
82
+ ];
83
+ function buildPermitTransferFromTypedData(input) {
84
+ return {
85
+ domain: {
86
+ name: "Permit2",
87
+ chainId: input.chainId,
88
+ verifyingContract: PERMIT2_ADDRESS
89
+ },
90
+ types: {
91
+ PermitTransferFrom: [
92
+ { name: "permitted", type: "TokenPermissions" },
93
+ { name: "spender", type: "address" },
94
+ { name: "nonce", type: "uint256" },
95
+ { name: "deadline", type: "uint256" }
96
+ ],
97
+ TokenPermissions: [
98
+ { name: "token", type: "address" },
99
+ { name: "amount", type: "uint256" }
100
+ ]
101
+ },
102
+ primaryType: "PermitTransferFrom",
103
+ message: input.message
104
+ };
105
+ }
106
+ function randomPermit2Nonce() {
107
+ const bytes = new Uint8Array(32);
108
+ globalThis.crypto.getRandomValues(bytes);
109
+ return BigInt(bytesToHex(bytes));
110
+ }
111
+ async function readPermit2Allowance(publicClient, token, owner) {
112
+ return publicClient.readContract({
113
+ address: token,
114
+ abi: ERC20_ALLOWANCE_ABI,
115
+ functionName: "allowance",
116
+ args: [owner, PERMIT2_ADDRESS]
117
+ });
118
+ }
119
+ async function readErc20Balance(publicClient, token, owner) {
120
+ return publicClient.readContract({
121
+ address: token,
122
+ abi: ERC20_ALLOWANCE_ABI,
123
+ functionName: "balanceOf",
124
+ args: [owner]
125
+ });
126
+ }
127
+
128
+ export {
129
+ OwneyError,
130
+ AgentNotFoundError,
131
+ NotConnectedError,
132
+ AgentChainIncompatibleError,
133
+ PERMIT2_ADDRESS,
134
+ MAX_UINT256,
135
+ ERC20_ALLOWANCE_ABI,
136
+ buildPermitTransferFromTypedData,
137
+ randomPermit2Nonce,
138
+ readPermit2Allowance,
139
+ readErc20Balance
140
+ };
package/dist/index.cjs CHANGED
@@ -80,8 +80,92 @@ var init_errors = __esm({
80
80
  }
81
81
  });
82
82
 
83
+ // src/lib/permit2.ts
84
+ function buildPermitTransferFromTypedData(input) {
85
+ return {
86
+ domain: {
87
+ name: "Permit2",
88
+ chainId: input.chainId,
89
+ verifyingContract: PERMIT2_ADDRESS
90
+ },
91
+ types: {
92
+ PermitTransferFrom: [
93
+ { name: "permitted", type: "TokenPermissions" },
94
+ { name: "spender", type: "address" },
95
+ { name: "nonce", type: "uint256" },
96
+ { name: "deadline", type: "uint256" }
97
+ ],
98
+ TokenPermissions: [
99
+ { name: "token", type: "address" },
100
+ { name: "amount", type: "uint256" }
101
+ ]
102
+ },
103
+ primaryType: "PermitTransferFrom",
104
+ message: input.message
105
+ };
106
+ }
107
+ function randomPermit2Nonce() {
108
+ const bytes = new Uint8Array(32);
109
+ globalThis.crypto.getRandomValues(bytes);
110
+ return BigInt((0, import_viem4.bytesToHex)(bytes));
111
+ }
112
+ async function readPermit2Allowance(publicClient, token, owner) {
113
+ return publicClient.readContract({
114
+ address: token,
115
+ abi: ERC20_ALLOWANCE_ABI,
116
+ functionName: "allowance",
117
+ args: [owner, PERMIT2_ADDRESS]
118
+ });
119
+ }
120
+ async function readErc20Balance(publicClient, token, owner) {
121
+ return publicClient.readContract({
122
+ address: token,
123
+ abi: ERC20_ALLOWANCE_ABI,
124
+ functionName: "balanceOf",
125
+ args: [owner]
126
+ });
127
+ }
128
+ var import_viem4, PERMIT2_ADDRESS, MAX_UINT256, ERC20_ALLOWANCE_ABI;
129
+ var init_permit2 = __esm({
130
+ "src/lib/permit2.ts"() {
131
+ "use strict";
132
+ import_viem4 = require("viem");
133
+ PERMIT2_ADDRESS = "0x000000000022D473030F116dDEE9F6B43aC78BA3";
134
+ MAX_UINT256 = 2n ** 256n - 1n;
135
+ ERC20_ALLOWANCE_ABI = [
136
+ {
137
+ type: "function",
138
+ name: "allowance",
139
+ stateMutability: "view",
140
+ inputs: [
141
+ { name: "owner", type: "address" },
142
+ { name: "spender", type: "address" }
143
+ ],
144
+ outputs: [{ name: "", type: "uint256" }]
145
+ },
146
+ {
147
+ type: "function",
148
+ name: "approve",
149
+ stateMutability: "nonpayable",
150
+ inputs: [
151
+ { name: "spender", type: "address" },
152
+ { name: "amount", type: "uint256" }
153
+ ],
154
+ outputs: [{ name: "", type: "bool" }]
155
+ },
156
+ {
157
+ type: "function",
158
+ name: "balanceOf",
159
+ stateMutability: "view",
160
+ inputs: [{ name: "account", type: "address" }],
161
+ outputs: [{ name: "", type: "uint256" }]
162
+ }
163
+ ];
164
+ }
165
+ });
166
+
83
167
  // src/agents/surfliquid/surfliquid.constants.ts
84
- var SURFLIQUID_CHAIN_ID, SURFLIQUID_CHAIN_NAME, SURFLIQUID_USDC_ADDRESS, SURFLIQUID_USDC_DECIMALS, SURFLIQUID_MIN_DEPOSIT, SURFLIQUID_SUPPORTED_ASSETS, SURFLIQUID_ACTION_MAP;
168
+ var SURFLIQUID_CHAIN_ID, SURFLIQUID_CHAIN_NAME, SURFLIQUID_USDC_ADDRESS, SURFLIQUID_USDC_DECIMALS, SURFLIQUID_MIN_DEPOSIT, SURFLIQUID_APPROVAL_TARGET, SURFLIQUID_SUPPORTED_ASSETS, SURFLIQUID_ACTION_MAP;
85
169
  var init_surfliquid_constants = __esm({
86
170
  "src/agents/surfliquid/surfliquid.constants.ts"() {
87
171
  "use strict";
@@ -90,6 +174,7 @@ var init_surfliquid_constants = __esm({
90
174
  SURFLIQUID_USDC_ADDRESS = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
91
175
  SURFLIQUID_USDC_DECIMALS = 6;
92
176
  SURFLIQUID_MIN_DEPOSIT = "0";
177
+ SURFLIQUID_APPROVAL_TARGET = 100000000000n;
93
178
  SURFLIQUID_SUPPORTED_ASSETS = [
94
179
  {
95
180
  chainId: SURFLIQUID_CHAIN_ID,
@@ -314,14 +399,16 @@ var surfliquid_agent_exports = {};
314
399
  __export(surfliquid_agent_exports, {
315
400
  SurfLiquidAgent: () => SurfLiquidAgent
316
401
  });
317
- var import_core_sdk2, import_viem5, APY_WINDOW_KEY2, SurfLiquidAgent;
402
+ var import_core_sdk2, import_viem5, import_chains2, APY_WINDOW_KEY2, SurfLiquidAgent;
318
403
  var init_surfliquid_agent = __esm({
319
404
  "src/agents/surfliquid/surfliquid.agent.ts"() {
320
405
  "use strict";
321
406
  import_core_sdk2 = require("@surf_liquid/core-sdk");
322
407
  import_viem5 = require("viem");
408
+ import_chains2 = require("viem/chains");
323
409
  init_errors();
324
410
  init_surfliquid_constants();
411
+ init_permit2();
325
412
  init_surfliquid_mapper();
326
413
  init_surfliquid_wallet_adapter();
327
414
  init_surfliquid_morpho();
@@ -397,6 +484,60 @@ var init_surfliquid_agent = __esm({
397
484
  const { vaultAddress } = await surf.deployVault();
398
485
  return vaultAddress;
399
486
  }
487
+ /**
488
+ * Grants the user's vault a standing USDC allowance so SurfLiquid's
489
+ * `autoApprove` has nothing to do — see {@link SURFLIQUID_APPROVAL_TARGET}
490
+ * for why one prompt per deposit is worth removing.
491
+ *
492
+ * Fails OPEN on a read error: if the allowance can't be checked we simply
493
+ * return and let SurfLiquid's own per-deposit approve run, because a flaky
494
+ * RPC must never block a deposit. A failed or rejected APPROVE does
495
+ * propagate — the user declined a transaction, and letting SurfLiquid
496
+ * immediately ask again for a smaller one is exactly the double prompt this
497
+ * removes.
498
+ */
499
+ async ensureVaultAllowance(state, vaultAddress, amount) {
500
+ const spender = vaultAddress;
501
+ const transport = (0, import_viem5.custom)(state.provider);
502
+ const publicClient = (0, import_viem5.createPublicClient)({ chain: import_chains2.base, transport });
503
+ let allowance;
504
+ try {
505
+ allowance = await publicClient.readContract({
506
+ address: SURFLIQUID_USDC_ADDRESS,
507
+ abi: ERC20_ALLOWANCE_ABI,
508
+ functionName: "allowance",
509
+ args: [state.walletAddress, spender]
510
+ });
511
+ } catch (error) {
512
+ console.warn(
513
+ "[owney-sdk] SurfLiquid allowance pre-check failed; deferring to its per-deposit approve:",
514
+ error instanceof Error ? error.message : String(error)
515
+ );
516
+ return;
517
+ }
518
+ if (allowance >= amount) return;
519
+ const target = amount > SURFLIQUID_APPROVAL_TARGET ? amount : SURFLIQUID_APPROVAL_TARGET;
520
+ const wallet = (0, import_viem5.createWalletClient)({
521
+ account: state.walletAddress,
522
+ chain: import_chains2.base,
523
+ transport
524
+ });
525
+ const hash = await wallet.writeContract({
526
+ address: SURFLIQUID_USDC_ADDRESS,
527
+ abi: ERC20_ALLOWANCE_ABI,
528
+ functionName: "approve",
529
+ args: [spender, target],
530
+ account: state.walletAddress,
531
+ chain: import_chains2.base
532
+ });
533
+ const receipt = await publicClient.waitForTransactionReceipt({
534
+ hash,
535
+ confirmations: 1
536
+ });
537
+ if (receipt.status !== "success") {
538
+ throw new Error(`SurfLiquid USDC approval reverted (tx ${hash})`);
539
+ }
540
+ }
400
541
  // --- IAgent: lifecycle ---
401
542
  async disconnect() {
402
543
  if (this.surf) {
@@ -415,6 +556,7 @@ var init_surfliquid_agent = __esm({
415
556
  surf,
416
557
  state.walletAddress
417
558
  );
559
+ await this.ensureVaultAllowance(state, smartWallet, BigInt(amount));
418
560
  const tx = await surf.deposit({
419
561
  asset: SURFLIQUID_USDC_ADDRESS,
420
562
  amount: human
@@ -2170,7 +2312,7 @@ function aggregateApyByChainAndAsset(agentApys, agentBalances) {
2170
2312
 
2171
2313
  // src/client.ts
2172
2314
  var import_viem6 = require("viem");
2173
- var import_chains2 = require("viem/chains");
2315
+ var import_chains3 = require("viem/chains");
2174
2316
 
2175
2317
  // src/lib/sponsored-deposit.ts
2176
2318
  init_errors();
@@ -2215,10 +2357,10 @@ function randomAuthNonce() {
2215
2357
  init_errors();
2216
2358
  var ROUTING_API_BASE_URL3 = "https://owney-routing-api-243946518160.europe-west4.run.app";
2217
2359
  async function postSponsorTransferAuth(input) {
2218
- const base3 = input.baseUrl ?? ROUTING_API_BASE_URL3;
2360
+ const base4 = input.baseUrl ?? ROUTING_API_BASE_URL3;
2219
2361
  let res;
2220
2362
  try {
2221
- res = await fetch(`${base3}/api/v1/sponsor/erc20-transfer-auth`, {
2363
+ res = await fetch(`${base4}/api/v1/sponsor/erc20-transfer-auth`, {
2222
2364
  method: "POST",
2223
2365
  headers: {
2224
2366
  "content-type": "application/json",
@@ -2255,10 +2397,10 @@ async function postSponsorTransferAuth(input) {
2255
2397
  return parsed.data;
2256
2398
  }
2257
2399
  async function postSponsorPermit2Transfer(input) {
2258
- const base3 = input.baseUrl ?? ROUTING_API_BASE_URL3;
2400
+ const base4 = input.baseUrl ?? ROUTING_API_BASE_URL3;
2259
2401
  let res;
2260
2402
  try {
2261
- res = await fetch(`${base3}/api/v1/sponsor/permit2-transfer`, {
2403
+ res = await fetch(`${base4}/api/v1/sponsor/permit2-transfer`, {
2262
2404
  method: "POST",
2263
2405
  headers: {
2264
2406
  "content-type": "application/json",
@@ -2293,11 +2435,11 @@ async function postSponsorPermit2Transfer(input) {
2293
2435
  return parsed.data;
2294
2436
  }
2295
2437
  async function getSponsorRelayerAddress(input) {
2296
- const base3 = input.baseUrl ?? ROUTING_API_BASE_URL3;
2438
+ const base4 = input.baseUrl ?? ROUTING_API_BASE_URL3;
2297
2439
  let res;
2298
2440
  try {
2299
2441
  res = await fetch(
2300
- `${base3}/api/v1/sponsor/relayer-address?chainId=${input.chainId}`,
2442
+ `${base4}/api/v1/sponsor/relayer-address?chainId=${input.chainId}`,
2301
2443
  {
2302
2444
  headers: { "x-owney-api-key": input.apiKey }
2303
2445
  }
@@ -2329,85 +2471,8 @@ async function getSponsorRelayerAddress(input) {
2329
2471
  return parsed.data.relayer;
2330
2472
  }
2331
2473
 
2332
- // src/lib/permit2.ts
2333
- var import_viem4 = require("viem");
2334
- var PERMIT2_ADDRESS = "0x000000000022D473030F116dDEE9F6B43aC78BA3";
2335
- var MAX_UINT256 = 2n ** 256n - 1n;
2336
- var ERC20_ALLOWANCE_ABI = [
2337
- {
2338
- type: "function",
2339
- name: "allowance",
2340
- stateMutability: "view",
2341
- inputs: [
2342
- { name: "owner", type: "address" },
2343
- { name: "spender", type: "address" }
2344
- ],
2345
- outputs: [{ name: "", type: "uint256" }]
2346
- },
2347
- {
2348
- type: "function",
2349
- name: "approve",
2350
- stateMutability: "nonpayable",
2351
- inputs: [
2352
- { name: "spender", type: "address" },
2353
- { name: "amount", type: "uint256" }
2354
- ],
2355
- outputs: [{ name: "", type: "bool" }]
2356
- },
2357
- {
2358
- type: "function",
2359
- name: "balanceOf",
2360
- stateMutability: "view",
2361
- inputs: [{ name: "account", type: "address" }],
2362
- outputs: [{ name: "", type: "uint256" }]
2363
- }
2364
- ];
2365
- function buildPermitTransferFromTypedData(input) {
2366
- return {
2367
- domain: {
2368
- name: "Permit2",
2369
- chainId: input.chainId,
2370
- verifyingContract: PERMIT2_ADDRESS
2371
- },
2372
- types: {
2373
- PermitTransferFrom: [
2374
- { name: "permitted", type: "TokenPermissions" },
2375
- { name: "spender", type: "address" },
2376
- { name: "nonce", type: "uint256" },
2377
- { name: "deadline", type: "uint256" }
2378
- ],
2379
- TokenPermissions: [
2380
- { name: "token", type: "address" },
2381
- { name: "amount", type: "uint256" }
2382
- ]
2383
- },
2384
- primaryType: "PermitTransferFrom",
2385
- message: input.message
2386
- };
2387
- }
2388
- function randomPermit2Nonce() {
2389
- const bytes = new Uint8Array(32);
2390
- globalThis.crypto.getRandomValues(bytes);
2391
- return BigInt((0, import_viem4.bytesToHex)(bytes));
2392
- }
2393
- async function readPermit2Allowance(publicClient, token, owner) {
2394
- return publicClient.readContract({
2395
- address: token,
2396
- abi: ERC20_ALLOWANCE_ABI,
2397
- functionName: "allowance",
2398
- args: [owner, PERMIT2_ADDRESS]
2399
- });
2400
- }
2401
- async function readErc20Balance(publicClient, token, owner) {
2402
- return publicClient.readContract({
2403
- address: token,
2404
- abi: ERC20_ALLOWANCE_ABI,
2405
- functionName: "balanceOf",
2406
- args: [owner]
2407
- });
2408
- }
2409
-
2410
2474
  // src/lib/sponsored-deposit.ts
2475
+ init_permit2();
2411
2476
  var AUTH_WINDOW_SECONDS = 15 * 60;
2412
2477
  function makeSponsoredDepositCallback(deps) {
2413
2478
  const post = deps.httpPost ?? postSponsorTransferAuth;
@@ -2482,6 +2547,7 @@ function makeSponsoredDepositCallback(deps) {
2482
2547
 
2483
2548
  // src/lib/sponsored-weth-deposit.ts
2484
2549
  init_errors();
2550
+ init_permit2();
2485
2551
  var PERMIT_WINDOW_SECONDS = 15 * 60;
2486
2552
  function makeSponsoredWethCallback(deps) {
2487
2553
  const get = deps.httpGet ?? getSponsorRelayerAddress;
@@ -2560,6 +2626,7 @@ function makeSponsoredWethCallback(deps) {
2560
2626
  }
2561
2627
 
2562
2628
  // src/client.ts
2629
+ init_permit2();
2563
2630
  function encodeMultiAgentCursor(map) {
2564
2631
  return Buffer.from(JSON.stringify(map), "utf8").toString("base64");
2565
2632
  }
@@ -2586,9 +2653,9 @@ var SPONSORED_USDC_BY_CHAIN = {
2586
2653
  1: "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"
2587
2654
  };
2588
2655
  var VIEM_CHAIN2 = {
2589
- 8453: import_chains2.base,
2590
- 42161: import_chains2.arbitrum,
2591
- 1: import_chains2.mainnet
2656
+ 8453: import_chains3.base,
2657
+ 42161: import_chains3.arbitrum,
2658
+ 1: import_chains3.mainnet
2592
2659
  };
2593
2660
  var AGENT_ELIGIBILITY_ORDER = ["surfliquid", "zyfai", "sail"];
2594
2661
  var SPONSORED_WETH_BY_CHAIN = {
package/dist/index.js CHANGED
@@ -1,9 +1,16 @@
1
1
  import {
2
2
  AgentChainIncompatibleError,
3
3
  AgentNotFoundError,
4
+ ERC20_ALLOWANCE_ABI,
5
+ MAX_UINT256,
4
6
  NotConnectedError,
5
- OwneyError
6
- } from "./chunk-GMNQBWUB.js";
7
+ OwneyError,
8
+ PERMIT2_ADDRESS,
9
+ buildPermitTransferFromTypedData,
10
+ randomPermit2Nonce,
11
+ readErc20Balance,
12
+ readPermit2Allowance
13
+ } from "./chunk-PWIKIQOX.js";
7
14
 
8
15
  // src/agents/zyfai/zyfai.agent.ts
9
16
  import { ZyfaiSDK } from "@zyfai/sdk";
@@ -1814,84 +1821,6 @@ async function getSponsorRelayerAddress(input) {
1814
1821
  return parsed.data.relayer;
1815
1822
  }
1816
1823
 
1817
- // src/lib/permit2.ts
1818
- import { bytesToHex as bytesToHex2 } from "viem";
1819
- var PERMIT2_ADDRESS = "0x000000000022D473030F116dDEE9F6B43aC78BA3";
1820
- var MAX_UINT256 = 2n ** 256n - 1n;
1821
- var ERC20_ALLOWANCE_ABI = [
1822
- {
1823
- type: "function",
1824
- name: "allowance",
1825
- stateMutability: "view",
1826
- inputs: [
1827
- { name: "owner", type: "address" },
1828
- { name: "spender", type: "address" }
1829
- ],
1830
- outputs: [{ name: "", type: "uint256" }]
1831
- },
1832
- {
1833
- type: "function",
1834
- name: "approve",
1835
- stateMutability: "nonpayable",
1836
- inputs: [
1837
- { name: "spender", type: "address" },
1838
- { name: "amount", type: "uint256" }
1839
- ],
1840
- outputs: [{ name: "", type: "bool" }]
1841
- },
1842
- {
1843
- type: "function",
1844
- name: "balanceOf",
1845
- stateMutability: "view",
1846
- inputs: [{ name: "account", type: "address" }],
1847
- outputs: [{ name: "", type: "uint256" }]
1848
- }
1849
- ];
1850
- function buildPermitTransferFromTypedData(input) {
1851
- return {
1852
- domain: {
1853
- name: "Permit2",
1854
- chainId: input.chainId,
1855
- verifyingContract: PERMIT2_ADDRESS
1856
- },
1857
- types: {
1858
- PermitTransferFrom: [
1859
- { name: "permitted", type: "TokenPermissions" },
1860
- { name: "spender", type: "address" },
1861
- { name: "nonce", type: "uint256" },
1862
- { name: "deadline", type: "uint256" }
1863
- ],
1864
- TokenPermissions: [
1865
- { name: "token", type: "address" },
1866
- { name: "amount", type: "uint256" }
1867
- ]
1868
- },
1869
- primaryType: "PermitTransferFrom",
1870
- message: input.message
1871
- };
1872
- }
1873
- function randomPermit2Nonce() {
1874
- const bytes = new Uint8Array(32);
1875
- globalThis.crypto.getRandomValues(bytes);
1876
- return BigInt(bytesToHex2(bytes));
1877
- }
1878
- async function readPermit2Allowance(publicClient, token, owner) {
1879
- return publicClient.readContract({
1880
- address: token,
1881
- abi: ERC20_ALLOWANCE_ABI,
1882
- functionName: "allowance",
1883
- args: [owner, PERMIT2_ADDRESS]
1884
- });
1885
- }
1886
- async function readErc20Balance(publicClient, token, owner) {
1887
- return publicClient.readContract({
1888
- address: token,
1889
- abi: ERC20_ALLOWANCE_ABI,
1890
- functionName: "balanceOf",
1891
- args: [owner]
1892
- });
1893
- }
1894
-
1895
1824
  // src/lib/sponsored-deposit.ts
1896
1825
  var AUTH_WINDOW_SECONDS = 15 * 60;
1897
1826
  function makeSponsoredDepositCallback(deps) {
@@ -2349,7 +2278,7 @@ var OwneySDK = class {
2349
2278
  }
2350
2279
  if (agentId === "surfliquid") {
2351
2280
  if (!projectName) return null;
2352
- const { SurfLiquidAgent } = await import("./surfliquid.agent-OMOYXWLP.js");
2281
+ const { SurfLiquidAgent } = await import("./surfliquid.agent-JOJJ3C5Y.js");
2353
2282
  return new SurfLiquidAgent({
2354
2283
  projectName,
2355
2284
  appId: key2,
@@ -1,10 +1,17 @@
1
1
  import {
2
+ ERC20_ALLOWANCE_ABI,
2
3
  OwneyError
3
- } from "./chunk-GMNQBWUB.js";
4
+ } from "./chunk-PWIKIQOX.js";
4
5
 
5
6
  // src/agents/surfliquid/surfliquid.agent.ts
6
7
  import { SurfClient } from "@surf_liquid/core-sdk";
7
- import { formatUnits } from "viem";
8
+ import {
9
+ createPublicClient,
10
+ createWalletClient,
11
+ custom,
12
+ formatUnits
13
+ } from "viem";
14
+ import { base } from "viem/chains";
8
15
 
9
16
  // src/agents/surfliquid/surfliquid.constants.ts
10
17
  var SURFLIQUID_CHAIN_ID = 8453;
@@ -12,6 +19,7 @@ var SURFLIQUID_CHAIN_NAME = "BASE";
12
19
  var SURFLIQUID_USDC_ADDRESS = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
13
20
  var SURFLIQUID_USDC_DECIMALS = 6;
14
21
  var SURFLIQUID_MIN_DEPOSIT = "0";
22
+ var SURFLIQUID_APPROVAL_TARGET = 100000000000n;
15
23
  var SURFLIQUID_SUPPORTED_ASSETS = [
16
24
  {
17
25
  chainId: SURFLIQUID_CHAIN_ID,
@@ -283,6 +291,60 @@ var SurfLiquidAgent = class {
283
291
  const { vaultAddress } = await surf.deployVault();
284
292
  return vaultAddress;
285
293
  }
294
+ /**
295
+ * Grants the user's vault a standing USDC allowance so SurfLiquid's
296
+ * `autoApprove` has nothing to do — see {@link SURFLIQUID_APPROVAL_TARGET}
297
+ * for why one prompt per deposit is worth removing.
298
+ *
299
+ * Fails OPEN on a read error: if the allowance can't be checked we simply
300
+ * return and let SurfLiquid's own per-deposit approve run, because a flaky
301
+ * RPC must never block a deposit. A failed or rejected APPROVE does
302
+ * propagate — the user declined a transaction, and letting SurfLiquid
303
+ * immediately ask again for a smaller one is exactly the double prompt this
304
+ * removes.
305
+ */
306
+ async ensureVaultAllowance(state, vaultAddress, amount) {
307
+ const spender = vaultAddress;
308
+ const transport = custom(state.provider);
309
+ const publicClient = createPublicClient({ chain: base, transport });
310
+ let allowance;
311
+ try {
312
+ allowance = await publicClient.readContract({
313
+ address: SURFLIQUID_USDC_ADDRESS,
314
+ abi: ERC20_ALLOWANCE_ABI,
315
+ functionName: "allowance",
316
+ args: [state.walletAddress, spender]
317
+ });
318
+ } catch (error) {
319
+ console.warn(
320
+ "[owney-sdk] SurfLiquid allowance pre-check failed; deferring to its per-deposit approve:",
321
+ error instanceof Error ? error.message : String(error)
322
+ );
323
+ return;
324
+ }
325
+ if (allowance >= amount) return;
326
+ const target = amount > SURFLIQUID_APPROVAL_TARGET ? amount : SURFLIQUID_APPROVAL_TARGET;
327
+ const wallet = createWalletClient({
328
+ account: state.walletAddress,
329
+ chain: base,
330
+ transport
331
+ });
332
+ const hash = await wallet.writeContract({
333
+ address: SURFLIQUID_USDC_ADDRESS,
334
+ abi: ERC20_ALLOWANCE_ABI,
335
+ functionName: "approve",
336
+ args: [spender, target],
337
+ account: state.walletAddress,
338
+ chain: base
339
+ });
340
+ const receipt = await publicClient.waitForTransactionReceipt({
341
+ hash,
342
+ confirmations: 1
343
+ });
344
+ if (receipt.status !== "success") {
345
+ throw new Error(`SurfLiquid USDC approval reverted (tx ${hash})`);
346
+ }
347
+ }
286
348
  // --- IAgent: lifecycle ---
287
349
  async disconnect() {
288
350
  if (this.surf) {
@@ -301,6 +363,7 @@ var SurfLiquidAgent = class {
301
363
  surf,
302
364
  state.walletAddress
303
365
  );
366
+ await this.ensureVaultAllowance(state, smartWallet, BigInt(amount));
304
367
  const tx = await surf.deposit({
305
368
  asset: SURFLIQUID_USDC_ADDRESS,
306
369
  amount: human
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@owney/sdk",
3
- "version": "0.6.9-beta.6",
3
+ "version": "0.6.9-beta.7",
4
4
  "type": "module",
5
5
  "main": "dist/index.cjs",
6
6
  "module": "dist/index.js",
@@ -1,55 +0,0 @@
1
- // src/errors.ts
2
- var OwneyError = class extends Error {
3
- code;
4
- details;
5
- agentId;
6
- constructor(code, message, details, agentId) {
7
- const prefix = agentId ? `[${code}][agent:${agentId}]` : `[${code}]`;
8
- super(`${prefix} ${message}`);
9
- this.name = "OwneyError";
10
- this.code = code;
11
- this.details = details;
12
- this.agentId = agentId;
13
- }
14
- };
15
- var AgentNotFoundError = class extends OwneyError {
16
- constructor(agentId, available) {
17
- super(
18
- "AGENT_NOT_FOUND",
19
- `Unknown agent "${agentId}". Available agents: ${available.join(", ")}`,
20
- { agentId, available },
21
- agentId
22
- );
23
- this.name = "AgentNotFoundError";
24
- }
25
- };
26
- var NotConnectedError = class extends OwneyError {
27
- constructor() {
28
- super("NOT_CONNECTED", "Not connected. Call sdk.connect(provider) first.");
29
- this.name = "NotConnectedError";
30
- }
31
- };
32
- var AgentChainIncompatibleError = class extends OwneyError {
33
- incompatibleAgents;
34
- connectedChainId;
35
- constructor(incompatibleAgents, connectedChainId) {
36
- const details = incompatibleAgents.map(
37
- ({ agentId, supportedChainIds }) => `"${agentId}" supports chains [${supportedChainIds.join(", ")}]`
38
- ).join("; ");
39
- super(
40
- "AGENT_CHAIN_INCOMPATIBLE",
41
- `Chain ${connectedChainId} is not supported by the following agents: ${details}`,
42
- { incompatibleAgents, connectedChainId }
43
- );
44
- this.name = "AgentChainIncompatibleError";
45
- this.incompatibleAgents = incompatibleAgents;
46
- this.connectedChainId = connectedChainId;
47
- }
48
- };
49
-
50
- export {
51
- OwneyError,
52
- AgentNotFoundError,
53
- NotConnectedError,
54
- AgentChainIncompatibleError
55
- };