@owney/sdk 0.4.6 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -934,6 +934,130 @@ function aggregateApyByChainAndAsset(agentApys, agentBalances) {
934
934
  return out;
935
935
  }
936
936
 
937
+ // src/client.ts
938
+ var import_viem3 = require("viem");
939
+ var import_chains = require("viem/chains");
940
+
941
+ // src/lib/transfer-auth.ts
942
+ var import_viem2 = require("viem");
943
+ var ERC20_META_ABI = [
944
+ { type: "function", name: "name", stateMutability: "view", inputs: [], outputs: [{ name: "", type: "string" }] },
945
+ { type: "function", name: "version", stateMutability: "view", inputs: [], outputs: [{ name: "", type: "string" }] }
946
+ ];
947
+ function buildTransferWithAuthorizationTypedData(input) {
948
+ return {
949
+ domain: { name: input.tokenName, version: input.tokenVersion, chainId: input.chainId, verifyingContract: input.token },
950
+ types: {
951
+ TransferWithAuthorization: [
952
+ { name: "from", type: "address" },
953
+ { name: "to", type: "address" },
954
+ { name: "value", type: "uint256" },
955
+ { name: "validAfter", type: "uint256" },
956
+ { name: "validBefore", type: "uint256" },
957
+ { name: "nonce", type: "bytes32" }
958
+ ]
959
+ },
960
+ primaryType: "TransferWithAuthorization",
961
+ message: input.message
962
+ };
963
+ }
964
+ async function readTokenMeta(publicClient, token) {
965
+ const [tokenName, tokenVersion] = await Promise.all([
966
+ publicClient.readContract({ address: token, abi: ERC20_META_ABI, functionName: "name" }),
967
+ publicClient.readContract({ address: token, abi: ERC20_META_ABI, functionName: "version" }).catch(() => "2")
968
+ ]);
969
+ return { tokenName, tokenVersion };
970
+ }
971
+ function randomAuthNonce() {
972
+ const bytes = new Uint8Array(32);
973
+ globalThis.crypto.getRandomValues(bytes);
974
+ return (0, import_viem2.bytesToHex)(bytes);
975
+ }
976
+
977
+ // src/lib/sponsor-client.ts
978
+ var ROUTING_API_BASE_URL3 = "https://owney-routing-api-243946518160.europe-west4.run.app";
979
+ async function postSponsorTransferAuth(input) {
980
+ const base2 = input.baseUrl ?? ROUTING_API_BASE_URL3;
981
+ let res;
982
+ try {
983
+ res = await fetch(`${base2}/api/v1/sponsor/erc20-transfer-auth`, {
984
+ method: "POST",
985
+ headers: { "content-type": "application/json", "x-owney-api-key": input.apiKey },
986
+ body: JSON.stringify(input.body)
987
+ });
988
+ } catch (networkError) {
989
+ throw new OwneyError(
990
+ "SPONSOR_REQUEST_FAILED",
991
+ `Sponsor API network error: ${networkError instanceof Error ? networkError.message : String(networkError)}`,
992
+ { cause: String(networkError) }
993
+ );
994
+ }
995
+ const text = await res.text();
996
+ let parsed = null;
997
+ try {
998
+ parsed = JSON.parse(text);
999
+ } catch {
1000
+ }
1001
+ if (!res.ok || !parsed?.success || !parsed.data) {
1002
+ throw new OwneyError(
1003
+ "SPONSOR_REQUEST_FAILED",
1004
+ `Sponsor API error ${res.status}: ${parsed?.message ?? text.slice(0, 500)}`,
1005
+ { statusCode: res.status, responseBody: text.slice(0, 500) }
1006
+ );
1007
+ }
1008
+ return parsed.data;
1009
+ }
1010
+
1011
+ // src/lib/sponsored-deposit.ts
1012
+ var AUTH_WINDOW_SECONDS = 15 * 60;
1013
+ function makeSponsoredDepositCallback(deps) {
1014
+ const post = deps.httpPost ?? postSponsorTransferAuth;
1015
+ return async (smartWallet, chainId, amount) => {
1016
+ const cid = chainId;
1017
+ const token = deps.tokenAddressByChain[cid];
1018
+ if (!token) {
1019
+ throw new OwneyError(
1020
+ "CHAIN_UNSUPPORTED",
1021
+ `No sponsored token configured for chain ${chainId}`
1022
+ );
1023
+ }
1024
+ const pub = deps.getPublicClient(cid);
1025
+ const wallet = deps.getWalletClient(cid);
1026
+ const { tokenName, tokenVersion } = await readTokenMeta(pub, token);
1027
+ const validAfter = 0n;
1028
+ const validBefore = BigInt(Math.floor(Date.now() / 1e3) + AUTH_WINDOW_SECONDS);
1029
+ const nonce = randomAuthNonce();
1030
+ const typedData = buildTransferWithAuthorizationTypedData({
1031
+ token,
1032
+ chainId: cid,
1033
+ tokenName,
1034
+ tokenVersion,
1035
+ message: { from: deps.ownerAddress, to: smartWallet, value: BigInt(amount), validAfter, validBefore, nonce }
1036
+ });
1037
+ const authSignature = await wallet.signTypedData(
1038
+ { account: deps.ownerAddress, ...typedData }
1039
+ );
1040
+ const result = await post({
1041
+ baseUrl: deps.baseUrl,
1042
+ apiKey: deps.apiKey,
1043
+ body: {
1044
+ chainId: cid,
1045
+ token,
1046
+ from: deps.ownerAddress,
1047
+ to: smartWallet,
1048
+ value: amount,
1049
+ validAfter: validAfter.toString(),
1050
+ validBefore: validBefore.toString(),
1051
+ nonce,
1052
+ authSignature,
1053
+ tokenName,
1054
+ tokenVersion
1055
+ }
1056
+ });
1057
+ return result.txHash;
1058
+ };
1059
+ }
1060
+
937
1061
  // src/client.ts
938
1062
  function encodeMultiAgentCursor(map) {
939
1063
  return Buffer.from(JSON.stringify(map), "utf8").toString("base64");
@@ -955,6 +1079,11 @@ function decodeMultiAgentCursor(token) {
955
1079
  }
956
1080
  return parsed;
957
1081
  }
1082
+ var SPONSORED_USDC_BY_CHAIN = {
1083
+ 8453: "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
1084
+ 42161: "0xaf88d065e77c8cc2239327c5edb3a432268e5831"
1085
+ };
1086
+ var VIEM_CHAIN = { 8453: import_chains.base, 42161: import_chains.arbitrum };
958
1087
  var OwneySDK = class {
959
1088
  agents = /* @__PURE__ */ new Map();
960
1089
  activeAgents = /* @__PURE__ */ new Set();
@@ -967,6 +1096,7 @@ var OwneySDK = class {
967
1096
  state = null;
968
1097
  apiKey;
969
1098
  zyfaiRpcUrls;
1099
+ cachedSponsoredCallback = null;
970
1100
  initializingAgentsPromise = null;
971
1101
  constructor(config) {
972
1102
  this.apiKey = config.apiKey;
@@ -990,6 +1120,7 @@ var OwneySDK = class {
990
1120
  );
991
1121
  }
992
1122
  this.state = { provider, walletAddress, chainId: null };
1123
+ this.cachedSponsoredCallback = null;
993
1124
  }
994
1125
  /**
995
1126
  * Disconnect from all agents and clear connection state.
@@ -1002,6 +1133,7 @@ var OwneySDK = class {
1002
1133
  this.activeAgents.clear();
1003
1134
  this.disabledAgents.clear();
1004
1135
  this.state = null;
1136
+ this.cachedSponsoredCallback = null;
1005
1137
  }
1006
1138
  isAgentDisabled(agentId) {
1007
1139
  return this.disabledAgents.has(agentId);
@@ -1035,6 +1167,46 @@ var OwneySDK = class {
1035
1167
  }
1036
1168
  return chainId;
1037
1169
  }
1170
+ requireConnectedProvider() {
1171
+ if (!this.state?.provider) {
1172
+ throw new OwneyError(
1173
+ "NOT_CONNECTED",
1174
+ "connect(provider) must be called before deposit",
1175
+ {}
1176
+ );
1177
+ }
1178
+ return this.state.provider;
1179
+ }
1180
+ /**
1181
+ * Lazily builds (and caches) the default EIP-3009 sponsored deposit callback
1182
+ * used when the caller omits `depositCallback`. Wraps the connected EIP-1193
1183
+ * provider with viem `custom(provider)` to read token meta and sign the
1184
+ * `TransferWithAuthorization`, then POSTs to the sponsor API.
1185
+ */
1186
+ getDefaultSponsoredCallback() {
1187
+ if (this.cachedSponsoredCallback)
1188
+ return this.cachedSponsoredCallback;
1189
+ const provider = this.requireConnectedProvider();
1190
+ const owner = this.state.walletAddress;
1191
+ this.cachedSponsoredCallback = makeSponsoredDepositCallback({
1192
+ apiKey: this.apiKey,
1193
+ ownerAddress: owner,
1194
+ tokenAddressByChain: SPONSORED_USDC_BY_CHAIN,
1195
+ // Casts work around viem's chain-narrowed Client vs the generic
1196
+ // PublicClient/WalletClient param types — structurally identical at
1197
+ // runtime, but the two share a name TS treats as unrelated.
1198
+ getPublicClient: (cid) => (0, import_viem3.createPublicClient)({
1199
+ chain: VIEM_CHAIN[cid],
1200
+ transport: (0, import_viem3.custom)(provider)
1201
+ }),
1202
+ getWalletClient: (cid) => (0, import_viem3.createWalletClient)({
1203
+ account: owner,
1204
+ chain: VIEM_CHAIN[cid],
1205
+ transport: (0, import_viem3.custom)(provider)
1206
+ })
1207
+ });
1208
+ return this.cachedSponsoredCallback;
1209
+ }
1038
1210
  getAgent(agentId) {
1039
1211
  const agent = this.agents.get(agentId);
1040
1212
  if (!agent) {
@@ -1188,6 +1360,7 @@ var OwneySDK = class {
1188
1360
  }
1189
1361
  const state = this.requireState();
1190
1362
  const chainId = this.requireChainId();
1363
+ const effectiveCallback = depositCallback ?? this.getDefaultSponsoredCallback();
1191
1364
  if (agentId) {
1192
1365
  if (this.isAgentDisabled(agentId)) {
1193
1366
  throw new OwneyError(
@@ -1202,7 +1375,7 @@ var OwneySDK = class {
1202
1375
  return withFailureReporting(
1203
1376
  this.apiKey,
1204
1377
  agent.id,
1205
- () => agent.deposit(state, chainId, amount, depositCallback)
1378
+ () => agent.deposit(state, chainId, amount, effectiveCallback)
1206
1379
  );
1207
1380
  }
1208
1381
  const totalAmount = BigInt(amount);
@@ -1236,7 +1409,7 @@ var OwneySDK = class {
1236
1409
  agentResults[agent.id] = await withFailureReporting(
1237
1410
  this.apiKey,
1238
1411
  agent.id,
1239
- () => agent.deposit(state, chainId, agentAmount, depositCallback)
1412
+ () => agent.deposit(state, chainId, agentAmount, effectiveCallback)
1240
1413
  );
1241
1414
  }
1242
1415
  return { agentResults };
@@ -1854,7 +2027,7 @@ var OwneySDK = class {
1854
2027
  };
1855
2028
 
1856
2029
  // src/agents/zyfai/zyfai.siwx.ts
1857
- var import_viem2 = require("viem");
2030
+ var import_viem4 = require("viem");
1858
2031
  var import_siwe = require("siwe");
1859
2032
  var import_sdk2 = require("@zyfai/sdk");
1860
2033
 
@@ -1936,7 +2109,7 @@ function buildSIWXConfig(deps) {
1936
2109
  issuedAt,
1937
2110
  toString() {
1938
2111
  return new import_siwe.SiweMessage({
1939
- address: (0, import_viem2.getAddress)(accountAddress),
2112
+ address: (0, import_viem4.getAddress)(accountAddress),
1940
2113
  chainId: numericChainId(chainId),
1941
2114
  domain,
1942
2115
  uri,
package/dist/index.d.cts CHANGED
@@ -101,7 +101,7 @@ type AgentsApyOptions = {
101
101
  type DepositOptions = {
102
102
  amount: string;
103
103
  asset: Asset;
104
- depositCallback: DepositCallback;
104
+ depositCallback?: DepositCallback;
105
105
  agentId?: AgentId;
106
106
  };
107
107
 
@@ -237,6 +237,7 @@ declare class OwneySDK {
237
237
  private state;
238
238
  private apiKey;
239
239
  private zyfaiRpcUrls?;
240
+ private cachedSponsoredCallback;
240
241
  private initializingAgentsPromise;
241
242
  constructor(config: OwneySDKConfig);
242
243
  /**
@@ -263,6 +264,14 @@ declare class OwneySDK {
263
264
  getActiveChainId(): number | null;
264
265
  private requireState;
265
266
  private requireChainId;
267
+ private requireConnectedProvider;
268
+ /**
269
+ * Lazily builds (and caches) the default EIP-3009 sponsored deposit callback
270
+ * used when the caller omits `depositCallback`. Wraps the connected EIP-1193
271
+ * provider with viem `custom(provider)` to read token meta and sign the
272
+ * `TransferWithAuthorization`, then POSTs to the sponsor API.
273
+ */
274
+ private getDefaultSponsoredCallback;
266
275
  private getAgent;
267
276
  private getActiveAgents;
268
277
  private ensureAgentsInitialized;
@@ -390,7 +399,7 @@ declare class OwneySDK {
390
399
  getAgentAllocation(): Promise<OwneyAgentAllocation>;
391
400
  }
392
401
 
393
- type OwneyErrorCode = "NOT_CONNECTED" | "NO_ACTIVE_CHAIN" | "WALLET_NO_ACCOUNTS" | "WALLET_ADDRESS_REQUIRED" | "AGENT_NOT_FOUND" | "AGENT_CHAIN_INCOMPATIBLE" | "AGENT_EMPTY_LIST" | "AGENT_DISABLED" | "CHAIN_UNSUPPORTED" | "CHAIN_NO_COMPATIBLE_AGENTS" | "ASSET_UNSUPPORTED" | "ASSET_NO_COMPATIBLE_AGENTS" | "DEPOSIT_AMOUNT_BELOW_MINIMUM" | "DEPOSIT_CALLBACK_REQUIRED" | "DEPOSIT_CALLBACK_INVALID" | "DEPOSIT_NO_PERMITTED_TOKENS" | "WITHDRAW_NO_PERMITTED_TOKENS" | "WITHDRAW_INSUFFICIENT_BALANCE" | "WITHDRAW_ALL_FAILED" | "WITHDRAW_PARTIAL_FAILURE" | "WITHDRAW_FAILED" | "API_ROUTING_ERROR" | "API_ROUTING_FAILED" | "API_SAIL_ERROR" | "API_SAIL_TIMEOUT" | "API_NO_AGENTS" | "BALANCE_ALL_FAILED" | "ALLOCATION_ALL_FAILED" | "VALIDATION_INVALID_DAYS";
402
+ type OwneyErrorCode = "NOT_CONNECTED" | "NO_ACTIVE_CHAIN" | "WALLET_NO_ACCOUNTS" | "WALLET_ADDRESS_REQUIRED" | "AGENT_NOT_FOUND" | "AGENT_CHAIN_INCOMPATIBLE" | "AGENT_EMPTY_LIST" | "AGENT_DISABLED" | "CHAIN_UNSUPPORTED" | "CHAIN_NO_COMPATIBLE_AGENTS" | "ASSET_UNSUPPORTED" | "ASSET_NO_COMPATIBLE_AGENTS" | "DEPOSIT_AMOUNT_BELOW_MINIMUM" | "DEPOSIT_CALLBACK_REQUIRED" | "DEPOSIT_CALLBACK_INVALID" | "DEPOSIT_NO_PERMITTED_TOKENS" | "WITHDRAW_NO_PERMITTED_TOKENS" | "WITHDRAW_INSUFFICIENT_BALANCE" | "WITHDRAW_ALL_FAILED" | "WITHDRAW_PARTIAL_FAILURE" | "WITHDRAW_FAILED" | "API_ROUTING_ERROR" | "API_ROUTING_FAILED" | "API_SAIL_ERROR" | "API_SAIL_TIMEOUT" | "API_NO_AGENTS" | "SPONSOR_REQUEST_FAILED" | "BALANCE_ALL_FAILED" | "ALLOCATION_ALL_FAILED" | "VALIDATION_INVALID_DAYS";
394
403
  declare class OwneyError extends Error {
395
404
  readonly code: OwneyErrorCode;
396
405
  readonly details?: Record<string, unknown>;
package/dist/index.d.ts CHANGED
@@ -101,7 +101,7 @@ type AgentsApyOptions = {
101
101
  type DepositOptions = {
102
102
  amount: string;
103
103
  asset: Asset;
104
- depositCallback: DepositCallback;
104
+ depositCallback?: DepositCallback;
105
105
  agentId?: AgentId;
106
106
  };
107
107
 
@@ -237,6 +237,7 @@ declare class OwneySDK {
237
237
  private state;
238
238
  private apiKey;
239
239
  private zyfaiRpcUrls?;
240
+ private cachedSponsoredCallback;
240
241
  private initializingAgentsPromise;
241
242
  constructor(config: OwneySDKConfig);
242
243
  /**
@@ -263,6 +264,14 @@ declare class OwneySDK {
263
264
  getActiveChainId(): number | null;
264
265
  private requireState;
265
266
  private requireChainId;
267
+ private requireConnectedProvider;
268
+ /**
269
+ * Lazily builds (and caches) the default EIP-3009 sponsored deposit callback
270
+ * used when the caller omits `depositCallback`. Wraps the connected EIP-1193
271
+ * provider with viem `custom(provider)` to read token meta and sign the
272
+ * `TransferWithAuthorization`, then POSTs to the sponsor API.
273
+ */
274
+ private getDefaultSponsoredCallback;
266
275
  private getAgent;
267
276
  private getActiveAgents;
268
277
  private ensureAgentsInitialized;
@@ -390,7 +399,7 @@ declare class OwneySDK {
390
399
  getAgentAllocation(): Promise<OwneyAgentAllocation>;
391
400
  }
392
401
 
393
- type OwneyErrorCode = "NOT_CONNECTED" | "NO_ACTIVE_CHAIN" | "WALLET_NO_ACCOUNTS" | "WALLET_ADDRESS_REQUIRED" | "AGENT_NOT_FOUND" | "AGENT_CHAIN_INCOMPATIBLE" | "AGENT_EMPTY_LIST" | "AGENT_DISABLED" | "CHAIN_UNSUPPORTED" | "CHAIN_NO_COMPATIBLE_AGENTS" | "ASSET_UNSUPPORTED" | "ASSET_NO_COMPATIBLE_AGENTS" | "DEPOSIT_AMOUNT_BELOW_MINIMUM" | "DEPOSIT_CALLBACK_REQUIRED" | "DEPOSIT_CALLBACK_INVALID" | "DEPOSIT_NO_PERMITTED_TOKENS" | "WITHDRAW_NO_PERMITTED_TOKENS" | "WITHDRAW_INSUFFICIENT_BALANCE" | "WITHDRAW_ALL_FAILED" | "WITHDRAW_PARTIAL_FAILURE" | "WITHDRAW_FAILED" | "API_ROUTING_ERROR" | "API_ROUTING_FAILED" | "API_SAIL_ERROR" | "API_SAIL_TIMEOUT" | "API_NO_AGENTS" | "BALANCE_ALL_FAILED" | "ALLOCATION_ALL_FAILED" | "VALIDATION_INVALID_DAYS";
402
+ type OwneyErrorCode = "NOT_CONNECTED" | "NO_ACTIVE_CHAIN" | "WALLET_NO_ACCOUNTS" | "WALLET_ADDRESS_REQUIRED" | "AGENT_NOT_FOUND" | "AGENT_CHAIN_INCOMPATIBLE" | "AGENT_EMPTY_LIST" | "AGENT_DISABLED" | "CHAIN_UNSUPPORTED" | "CHAIN_NO_COMPATIBLE_AGENTS" | "ASSET_UNSUPPORTED" | "ASSET_NO_COMPATIBLE_AGENTS" | "DEPOSIT_AMOUNT_BELOW_MINIMUM" | "DEPOSIT_CALLBACK_REQUIRED" | "DEPOSIT_CALLBACK_INVALID" | "DEPOSIT_NO_PERMITTED_TOKENS" | "WITHDRAW_NO_PERMITTED_TOKENS" | "WITHDRAW_INSUFFICIENT_BALANCE" | "WITHDRAW_ALL_FAILED" | "WITHDRAW_PARTIAL_FAILURE" | "WITHDRAW_FAILED" | "API_ROUTING_ERROR" | "API_ROUTING_FAILED" | "API_SAIL_ERROR" | "API_SAIL_TIMEOUT" | "API_NO_AGENTS" | "SPONSOR_REQUEST_FAILED" | "BALANCE_ALL_FAILED" | "ALLOCATION_ALL_FAILED" | "VALIDATION_INVALID_DAYS";
394
403
  declare class OwneyError extends Error {
395
404
  readonly code: OwneyErrorCode;
396
405
  readonly details?: Record<string, unknown>;
package/dist/index.js CHANGED
@@ -902,6 +902,134 @@ function aggregateApyByChainAndAsset(agentApys, agentBalances) {
902
902
  return out;
903
903
  }
904
904
 
905
+ // src/client.ts
906
+ import {
907
+ createPublicClient,
908
+ createWalletClient,
909
+ custom
910
+ } from "viem";
911
+ import { base, arbitrum } from "viem/chains";
912
+
913
+ // src/lib/transfer-auth.ts
914
+ import { bytesToHex } from "viem";
915
+ var ERC20_META_ABI = [
916
+ { type: "function", name: "name", stateMutability: "view", inputs: [], outputs: [{ name: "", type: "string" }] },
917
+ { type: "function", name: "version", stateMutability: "view", inputs: [], outputs: [{ name: "", type: "string" }] }
918
+ ];
919
+ function buildTransferWithAuthorizationTypedData(input) {
920
+ return {
921
+ domain: { name: input.tokenName, version: input.tokenVersion, chainId: input.chainId, verifyingContract: input.token },
922
+ types: {
923
+ TransferWithAuthorization: [
924
+ { name: "from", type: "address" },
925
+ { name: "to", type: "address" },
926
+ { name: "value", type: "uint256" },
927
+ { name: "validAfter", type: "uint256" },
928
+ { name: "validBefore", type: "uint256" },
929
+ { name: "nonce", type: "bytes32" }
930
+ ]
931
+ },
932
+ primaryType: "TransferWithAuthorization",
933
+ message: input.message
934
+ };
935
+ }
936
+ async function readTokenMeta(publicClient, token) {
937
+ const [tokenName, tokenVersion] = await Promise.all([
938
+ publicClient.readContract({ address: token, abi: ERC20_META_ABI, functionName: "name" }),
939
+ publicClient.readContract({ address: token, abi: ERC20_META_ABI, functionName: "version" }).catch(() => "2")
940
+ ]);
941
+ return { tokenName, tokenVersion };
942
+ }
943
+ function randomAuthNonce() {
944
+ const bytes = new Uint8Array(32);
945
+ globalThis.crypto.getRandomValues(bytes);
946
+ return bytesToHex(bytes);
947
+ }
948
+
949
+ // src/lib/sponsor-client.ts
950
+ var ROUTING_API_BASE_URL3 = "https://owney-routing-api-243946518160.europe-west4.run.app";
951
+ async function postSponsorTransferAuth(input) {
952
+ const base2 = input.baseUrl ?? ROUTING_API_BASE_URL3;
953
+ let res;
954
+ try {
955
+ res = await fetch(`${base2}/api/v1/sponsor/erc20-transfer-auth`, {
956
+ method: "POST",
957
+ headers: { "content-type": "application/json", "x-owney-api-key": input.apiKey },
958
+ body: JSON.stringify(input.body)
959
+ });
960
+ } catch (networkError) {
961
+ throw new OwneyError(
962
+ "SPONSOR_REQUEST_FAILED",
963
+ `Sponsor API network error: ${networkError instanceof Error ? networkError.message : String(networkError)}`,
964
+ { cause: String(networkError) }
965
+ );
966
+ }
967
+ const text = await res.text();
968
+ let parsed = null;
969
+ try {
970
+ parsed = JSON.parse(text);
971
+ } catch {
972
+ }
973
+ if (!res.ok || !parsed?.success || !parsed.data) {
974
+ throw new OwneyError(
975
+ "SPONSOR_REQUEST_FAILED",
976
+ `Sponsor API error ${res.status}: ${parsed?.message ?? text.slice(0, 500)}`,
977
+ { statusCode: res.status, responseBody: text.slice(0, 500) }
978
+ );
979
+ }
980
+ return parsed.data;
981
+ }
982
+
983
+ // src/lib/sponsored-deposit.ts
984
+ var AUTH_WINDOW_SECONDS = 15 * 60;
985
+ function makeSponsoredDepositCallback(deps) {
986
+ const post = deps.httpPost ?? postSponsorTransferAuth;
987
+ return async (smartWallet, chainId, amount) => {
988
+ const cid = chainId;
989
+ const token = deps.tokenAddressByChain[cid];
990
+ if (!token) {
991
+ throw new OwneyError(
992
+ "CHAIN_UNSUPPORTED",
993
+ `No sponsored token configured for chain ${chainId}`
994
+ );
995
+ }
996
+ const pub = deps.getPublicClient(cid);
997
+ const wallet = deps.getWalletClient(cid);
998
+ const { tokenName, tokenVersion } = await readTokenMeta(pub, token);
999
+ const validAfter = 0n;
1000
+ const validBefore = BigInt(Math.floor(Date.now() / 1e3) + AUTH_WINDOW_SECONDS);
1001
+ const nonce = randomAuthNonce();
1002
+ const typedData = buildTransferWithAuthorizationTypedData({
1003
+ token,
1004
+ chainId: cid,
1005
+ tokenName,
1006
+ tokenVersion,
1007
+ message: { from: deps.ownerAddress, to: smartWallet, value: BigInt(amount), validAfter, validBefore, nonce }
1008
+ });
1009
+ const authSignature = await wallet.signTypedData(
1010
+ { account: deps.ownerAddress, ...typedData }
1011
+ );
1012
+ const result = await post({
1013
+ baseUrl: deps.baseUrl,
1014
+ apiKey: deps.apiKey,
1015
+ body: {
1016
+ chainId: cid,
1017
+ token,
1018
+ from: deps.ownerAddress,
1019
+ to: smartWallet,
1020
+ value: amount,
1021
+ validAfter: validAfter.toString(),
1022
+ validBefore: validBefore.toString(),
1023
+ nonce,
1024
+ authSignature,
1025
+ tokenName,
1026
+ tokenVersion
1027
+ }
1028
+ });
1029
+ return result.txHash;
1030
+ };
1031
+ }
1032
+
905
1033
  // src/client.ts
906
1034
  function encodeMultiAgentCursor(map) {
907
1035
  return Buffer.from(JSON.stringify(map), "utf8").toString("base64");
@@ -923,6 +1051,11 @@ function decodeMultiAgentCursor(token) {
923
1051
  }
924
1052
  return parsed;
925
1053
  }
1054
+ var SPONSORED_USDC_BY_CHAIN = {
1055
+ 8453: "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
1056
+ 42161: "0xaf88d065e77c8cc2239327c5edb3a432268e5831"
1057
+ };
1058
+ var VIEM_CHAIN = { 8453: base, 42161: arbitrum };
926
1059
  var OwneySDK = class {
927
1060
  agents = /* @__PURE__ */ new Map();
928
1061
  activeAgents = /* @__PURE__ */ new Set();
@@ -935,6 +1068,7 @@ var OwneySDK = class {
935
1068
  state = null;
936
1069
  apiKey;
937
1070
  zyfaiRpcUrls;
1071
+ cachedSponsoredCallback = null;
938
1072
  initializingAgentsPromise = null;
939
1073
  constructor(config) {
940
1074
  this.apiKey = config.apiKey;
@@ -958,6 +1092,7 @@ var OwneySDK = class {
958
1092
  );
959
1093
  }
960
1094
  this.state = { provider, walletAddress, chainId: null };
1095
+ this.cachedSponsoredCallback = null;
961
1096
  }
962
1097
  /**
963
1098
  * Disconnect from all agents and clear connection state.
@@ -970,6 +1105,7 @@ var OwneySDK = class {
970
1105
  this.activeAgents.clear();
971
1106
  this.disabledAgents.clear();
972
1107
  this.state = null;
1108
+ this.cachedSponsoredCallback = null;
973
1109
  }
974
1110
  isAgentDisabled(agentId) {
975
1111
  return this.disabledAgents.has(agentId);
@@ -1003,6 +1139,46 @@ var OwneySDK = class {
1003
1139
  }
1004
1140
  return chainId;
1005
1141
  }
1142
+ requireConnectedProvider() {
1143
+ if (!this.state?.provider) {
1144
+ throw new OwneyError(
1145
+ "NOT_CONNECTED",
1146
+ "connect(provider) must be called before deposit",
1147
+ {}
1148
+ );
1149
+ }
1150
+ return this.state.provider;
1151
+ }
1152
+ /**
1153
+ * Lazily builds (and caches) the default EIP-3009 sponsored deposit callback
1154
+ * used when the caller omits `depositCallback`. Wraps the connected EIP-1193
1155
+ * provider with viem `custom(provider)` to read token meta and sign the
1156
+ * `TransferWithAuthorization`, then POSTs to the sponsor API.
1157
+ */
1158
+ getDefaultSponsoredCallback() {
1159
+ if (this.cachedSponsoredCallback)
1160
+ return this.cachedSponsoredCallback;
1161
+ const provider = this.requireConnectedProvider();
1162
+ const owner = this.state.walletAddress;
1163
+ this.cachedSponsoredCallback = makeSponsoredDepositCallback({
1164
+ apiKey: this.apiKey,
1165
+ ownerAddress: owner,
1166
+ tokenAddressByChain: SPONSORED_USDC_BY_CHAIN,
1167
+ // Casts work around viem's chain-narrowed Client vs the generic
1168
+ // PublicClient/WalletClient param types — structurally identical at
1169
+ // runtime, but the two share a name TS treats as unrelated.
1170
+ getPublicClient: (cid) => createPublicClient({
1171
+ chain: VIEM_CHAIN[cid],
1172
+ transport: custom(provider)
1173
+ }),
1174
+ getWalletClient: (cid) => createWalletClient({
1175
+ account: owner,
1176
+ chain: VIEM_CHAIN[cid],
1177
+ transport: custom(provider)
1178
+ })
1179
+ });
1180
+ return this.cachedSponsoredCallback;
1181
+ }
1006
1182
  getAgent(agentId) {
1007
1183
  const agent = this.agents.get(agentId);
1008
1184
  if (!agent) {
@@ -1156,6 +1332,7 @@ var OwneySDK = class {
1156
1332
  }
1157
1333
  const state = this.requireState();
1158
1334
  const chainId = this.requireChainId();
1335
+ const effectiveCallback = depositCallback ?? this.getDefaultSponsoredCallback();
1159
1336
  if (agentId) {
1160
1337
  if (this.isAgentDisabled(agentId)) {
1161
1338
  throw new OwneyError(
@@ -1170,7 +1347,7 @@ var OwneySDK = class {
1170
1347
  return withFailureReporting(
1171
1348
  this.apiKey,
1172
1349
  agent.id,
1173
- () => agent.deposit(state, chainId, amount, depositCallback)
1350
+ () => agent.deposit(state, chainId, amount, effectiveCallback)
1174
1351
  );
1175
1352
  }
1176
1353
  const totalAmount = BigInt(amount);
@@ -1204,7 +1381,7 @@ var OwneySDK = class {
1204
1381
  agentResults[agent.id] = await withFailureReporting(
1205
1382
  this.apiKey,
1206
1383
  agent.id,
1207
- () => agent.deposit(state, chainId, agentAmount, depositCallback)
1384
+ () => agent.deposit(state, chainId, agentAmount, effectiveCallback)
1208
1385
  );
1209
1386
  }
1210
1387
  return { agentResults };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@owney/sdk",
3
- "version": "0.4.6",
3
+ "version": "0.5.0",
4
4
  "type": "module",
5
5
  "main": "dist/index.cjs",
6
6
  "module": "dist/index.js",