@owney/sdk 0.4.5 → 0.5.0-beta.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
@@ -933,6 +933,130 @@ function aggregateApyByChainAndAsset(agentApys, agentBalances) {
933
933
  return out;
934
934
  }
935
935
 
936
+ // src/client.ts
937
+ var import_viem3 = require("viem");
938
+ var import_chains = require("viem/chains");
939
+
940
+ // src/lib/transfer-auth.ts
941
+ var import_viem2 = require("viem");
942
+ var ERC20_META_ABI = [
943
+ { type: "function", name: "name", stateMutability: "view", inputs: [], outputs: [{ name: "", type: "string" }] },
944
+ { type: "function", name: "version", stateMutability: "view", inputs: [], outputs: [{ name: "", type: "string" }] }
945
+ ];
946
+ function buildTransferWithAuthorizationTypedData(input) {
947
+ return {
948
+ domain: { name: input.tokenName, version: input.tokenVersion, chainId: input.chainId, verifyingContract: input.token },
949
+ types: {
950
+ TransferWithAuthorization: [
951
+ { name: "from", type: "address" },
952
+ { name: "to", type: "address" },
953
+ { name: "value", type: "uint256" },
954
+ { name: "validAfter", type: "uint256" },
955
+ { name: "validBefore", type: "uint256" },
956
+ { name: "nonce", type: "bytes32" }
957
+ ]
958
+ },
959
+ primaryType: "TransferWithAuthorization",
960
+ message: input.message
961
+ };
962
+ }
963
+ async function readTokenMeta(publicClient, token) {
964
+ const [tokenName, tokenVersion] = await Promise.all([
965
+ publicClient.readContract({ address: token, abi: ERC20_META_ABI, functionName: "name" }),
966
+ publicClient.readContract({ address: token, abi: ERC20_META_ABI, functionName: "version" }).catch(() => "2")
967
+ ]);
968
+ return { tokenName, tokenVersion };
969
+ }
970
+ function randomAuthNonce() {
971
+ const bytes = new Uint8Array(32);
972
+ globalThis.crypto.getRandomValues(bytes);
973
+ return (0, import_viem2.bytesToHex)(bytes);
974
+ }
975
+
976
+ // src/lib/sponsor-client.ts
977
+ var ROUTING_API_BASE_URL3 = "https://owney-routing-api-243946518160.europe-west4.run.app";
978
+ async function postSponsorTransferAuth(input) {
979
+ const base2 = input.baseUrl ?? ROUTING_API_BASE_URL3;
980
+ let res;
981
+ try {
982
+ res = await fetch(`${base2}/api/v1/sponsor/erc20-transfer-auth`, {
983
+ method: "POST",
984
+ headers: { "content-type": "application/json", "x-owney-api-key": input.apiKey },
985
+ body: JSON.stringify(input.body)
986
+ });
987
+ } catch (networkError) {
988
+ throw new OwneyError(
989
+ "SPONSOR_REQUEST_FAILED",
990
+ `Sponsor API network error: ${networkError instanceof Error ? networkError.message : String(networkError)}`,
991
+ { cause: String(networkError) }
992
+ );
993
+ }
994
+ const text = await res.text();
995
+ let parsed = null;
996
+ try {
997
+ parsed = JSON.parse(text);
998
+ } catch {
999
+ }
1000
+ if (!res.ok || !parsed?.success || !parsed.data) {
1001
+ throw new OwneyError(
1002
+ "SPONSOR_REQUEST_FAILED",
1003
+ `Sponsor API error ${res.status}: ${parsed?.message ?? text.slice(0, 500)}`,
1004
+ { statusCode: res.status, responseBody: text.slice(0, 500) }
1005
+ );
1006
+ }
1007
+ return parsed.data;
1008
+ }
1009
+
1010
+ // src/lib/sponsored-deposit.ts
1011
+ var AUTH_WINDOW_SECONDS = 15 * 60;
1012
+ function makeSponsoredDepositCallback(deps) {
1013
+ const post = deps.httpPost ?? postSponsorTransferAuth;
1014
+ return async (smartWallet, chainId, amount) => {
1015
+ const cid = chainId;
1016
+ const token = deps.tokenAddressByChain[cid];
1017
+ if (!token) {
1018
+ throw new OwneyError(
1019
+ "CHAIN_UNSUPPORTED",
1020
+ `No sponsored token configured for chain ${chainId}`
1021
+ );
1022
+ }
1023
+ const pub = deps.getPublicClient(cid);
1024
+ const wallet = deps.getWalletClient(cid);
1025
+ const { tokenName, tokenVersion } = await readTokenMeta(pub, token);
1026
+ const validAfter = 0n;
1027
+ const validBefore = BigInt(Math.floor(Date.now() / 1e3) + AUTH_WINDOW_SECONDS);
1028
+ const nonce = randomAuthNonce();
1029
+ const typedData = buildTransferWithAuthorizationTypedData({
1030
+ token,
1031
+ chainId: cid,
1032
+ tokenName,
1033
+ tokenVersion,
1034
+ message: { from: deps.ownerAddress, to: smartWallet, value: BigInt(amount), validAfter, validBefore, nonce }
1035
+ });
1036
+ const authSignature = await wallet.signTypedData(
1037
+ { account: deps.ownerAddress, ...typedData }
1038
+ );
1039
+ const result = await post({
1040
+ baseUrl: deps.baseUrl,
1041
+ apiKey: deps.apiKey,
1042
+ body: {
1043
+ chainId: cid,
1044
+ token,
1045
+ from: deps.ownerAddress,
1046
+ to: smartWallet,
1047
+ value: amount,
1048
+ validAfter: validAfter.toString(),
1049
+ validBefore: validBefore.toString(),
1050
+ nonce,
1051
+ authSignature,
1052
+ tokenName,
1053
+ tokenVersion
1054
+ }
1055
+ });
1056
+ return result.txHash;
1057
+ };
1058
+ }
1059
+
936
1060
  // src/client.ts
937
1061
  function encodeMultiAgentCursor(map) {
938
1062
  return Buffer.from(JSON.stringify(map), "utf8").toString("base64");
@@ -954,6 +1078,11 @@ function decodeMultiAgentCursor(token) {
954
1078
  }
955
1079
  return parsed;
956
1080
  }
1081
+ var SPONSORED_USDC_BY_CHAIN = {
1082
+ 8453: "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
1083
+ 42161: "0xaf88d065e77c8cc2239327c5edb3a432268e5831"
1084
+ };
1085
+ var VIEM_CHAIN = { 8453: import_chains.base, 42161: import_chains.arbitrum };
957
1086
  var OwneySDK = class {
958
1087
  agents = /* @__PURE__ */ new Map();
959
1088
  activeAgents = /* @__PURE__ */ new Set();
@@ -966,6 +1095,7 @@ var OwneySDK = class {
966
1095
  state = null;
967
1096
  apiKey;
968
1097
  zyfaiRpcUrls;
1098
+ cachedSponsoredCallback = null;
969
1099
  initializingAgentsPromise = null;
970
1100
  constructor(config) {
971
1101
  this.apiKey = config.apiKey;
@@ -989,6 +1119,7 @@ var OwneySDK = class {
989
1119
  );
990
1120
  }
991
1121
  this.state = { provider, walletAddress, chainId: null };
1122
+ this.cachedSponsoredCallback = null;
992
1123
  }
993
1124
  /**
994
1125
  * Disconnect from all agents and clear connection state.
@@ -1001,6 +1132,7 @@ var OwneySDK = class {
1001
1132
  this.activeAgents.clear();
1002
1133
  this.disabledAgents.clear();
1003
1134
  this.state = null;
1135
+ this.cachedSponsoredCallback = null;
1004
1136
  }
1005
1137
  isAgentDisabled(agentId) {
1006
1138
  return this.disabledAgents.has(agentId);
@@ -1034,6 +1166,46 @@ var OwneySDK = class {
1034
1166
  }
1035
1167
  return chainId;
1036
1168
  }
1169
+ requireConnectedProvider() {
1170
+ if (!this.state?.provider) {
1171
+ throw new OwneyError(
1172
+ "NOT_CONNECTED",
1173
+ "connect(provider) must be called before deposit",
1174
+ {}
1175
+ );
1176
+ }
1177
+ return this.state.provider;
1178
+ }
1179
+ /**
1180
+ * Lazily builds (and caches) the default EIP-3009 sponsored deposit callback
1181
+ * used when the caller omits `depositCallback`. Wraps the connected EIP-1193
1182
+ * provider with viem `custom(provider)` to read token meta and sign the
1183
+ * `TransferWithAuthorization`, then POSTs to the sponsor API.
1184
+ */
1185
+ getDefaultSponsoredCallback() {
1186
+ if (this.cachedSponsoredCallback)
1187
+ return this.cachedSponsoredCallback;
1188
+ const provider = this.requireConnectedProvider();
1189
+ const owner = this.state.walletAddress;
1190
+ this.cachedSponsoredCallback = makeSponsoredDepositCallback({
1191
+ apiKey: this.apiKey,
1192
+ ownerAddress: owner,
1193
+ tokenAddressByChain: SPONSORED_USDC_BY_CHAIN,
1194
+ // Casts work around viem's chain-narrowed Client vs the generic
1195
+ // PublicClient/WalletClient param types — structurally identical at
1196
+ // runtime, but the two share a name TS treats as unrelated.
1197
+ getPublicClient: (cid) => (0, import_viem3.createPublicClient)({
1198
+ chain: VIEM_CHAIN[cid],
1199
+ transport: (0, import_viem3.custom)(provider)
1200
+ }),
1201
+ getWalletClient: (cid) => (0, import_viem3.createWalletClient)({
1202
+ account: owner,
1203
+ chain: VIEM_CHAIN[cid],
1204
+ transport: (0, import_viem3.custom)(provider)
1205
+ })
1206
+ });
1207
+ return this.cachedSponsoredCallback;
1208
+ }
1037
1209
  getAgent(agentId) {
1038
1210
  const agent = this.agents.get(agentId);
1039
1211
  if (!agent) {
@@ -1187,6 +1359,7 @@ var OwneySDK = class {
1187
1359
  }
1188
1360
  const state = this.requireState();
1189
1361
  const chainId = this.requireChainId();
1362
+ const effectiveCallback = depositCallback ?? this.getDefaultSponsoredCallback();
1190
1363
  if (agentId) {
1191
1364
  if (this.isAgentDisabled(agentId)) {
1192
1365
  throw new OwneyError(
@@ -1201,7 +1374,7 @@ var OwneySDK = class {
1201
1374
  return withFailureReporting(
1202
1375
  this.apiKey,
1203
1376
  agent.id,
1204
- () => agent.deposit(state, chainId, amount, depositCallback)
1377
+ () => agent.deposit(state, chainId, amount, effectiveCallback)
1205
1378
  );
1206
1379
  }
1207
1380
  const totalAmount = BigInt(amount);
@@ -1235,7 +1408,7 @@ var OwneySDK = class {
1235
1408
  agentResults[agent.id] = await withFailureReporting(
1236
1409
  this.apiKey,
1237
1410
  agent.id,
1238
- () => agent.deposit(state, chainId, agentAmount, depositCallback)
1411
+ () => agent.deposit(state, chainId, agentAmount, effectiveCallback)
1239
1412
  );
1240
1413
  }
1241
1414
  return { agentResults };
package/dist/index.d.cts CHANGED
@@ -99,7 +99,7 @@ type AgentsApyOptions = {
99
99
  type DepositOptions = {
100
100
  amount: string;
101
101
  asset: Asset;
102
- depositCallback: DepositCallback;
102
+ depositCallback?: DepositCallback;
103
103
  agentId?: AgentId;
104
104
  };
105
105
 
@@ -235,6 +235,7 @@ declare class OwneySDK {
235
235
  private state;
236
236
  private apiKey;
237
237
  private zyfaiRpcUrls?;
238
+ private cachedSponsoredCallback;
238
239
  private initializingAgentsPromise;
239
240
  constructor(config: OwneySDKConfig);
240
241
  /**
@@ -261,6 +262,14 @@ declare class OwneySDK {
261
262
  getActiveChainId(): number | null;
262
263
  private requireState;
263
264
  private requireChainId;
265
+ private requireConnectedProvider;
266
+ /**
267
+ * Lazily builds (and caches) the default EIP-3009 sponsored deposit callback
268
+ * used when the caller omits `depositCallback`. Wraps the connected EIP-1193
269
+ * provider with viem `custom(provider)` to read token meta and sign the
270
+ * `TransferWithAuthorization`, then POSTs to the sponsor API.
271
+ */
272
+ private getDefaultSponsoredCallback;
264
273
  private getAgent;
265
274
  private getActiveAgents;
266
275
  private ensureAgentsInitialized;
@@ -388,7 +397,7 @@ declare class OwneySDK {
388
397
  getAgentAllocation(): Promise<OwneyAgentAllocation>;
389
398
  }
390
399
 
391
- 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";
400
+ 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";
392
401
  declare class OwneyError extends Error {
393
402
  readonly code: OwneyErrorCode;
394
403
  readonly details?: Record<string, unknown>;
package/dist/index.d.ts CHANGED
@@ -99,7 +99,7 @@ type AgentsApyOptions = {
99
99
  type DepositOptions = {
100
100
  amount: string;
101
101
  asset: Asset;
102
- depositCallback: DepositCallback;
102
+ depositCallback?: DepositCallback;
103
103
  agentId?: AgentId;
104
104
  };
105
105
 
@@ -235,6 +235,7 @@ declare class OwneySDK {
235
235
  private state;
236
236
  private apiKey;
237
237
  private zyfaiRpcUrls?;
238
+ private cachedSponsoredCallback;
238
239
  private initializingAgentsPromise;
239
240
  constructor(config: OwneySDKConfig);
240
241
  /**
@@ -261,6 +262,14 @@ declare class OwneySDK {
261
262
  getActiveChainId(): number | null;
262
263
  private requireState;
263
264
  private requireChainId;
265
+ private requireConnectedProvider;
266
+ /**
267
+ * Lazily builds (and caches) the default EIP-3009 sponsored deposit callback
268
+ * used when the caller omits `depositCallback`. Wraps the connected EIP-1193
269
+ * provider with viem `custom(provider)` to read token meta and sign the
270
+ * `TransferWithAuthorization`, then POSTs to the sponsor API.
271
+ */
272
+ private getDefaultSponsoredCallback;
264
273
  private getAgent;
265
274
  private getActiveAgents;
266
275
  private ensureAgentsInitialized;
@@ -388,7 +397,7 @@ declare class OwneySDK {
388
397
  getAgentAllocation(): Promise<OwneyAgentAllocation>;
389
398
  }
390
399
 
391
- 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";
400
+ 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";
392
401
  declare class OwneyError extends Error {
393
402
  readonly code: OwneyErrorCode;
394
403
  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.5",
3
+ "version": "0.5.0-beta.0",
4
4
  "type": "module",
5
5
  "main": "dist/index.cjs",
6
6
  "module": "dist/index.js",
@@ -35,4 +35,4 @@
35
35
  "publishConfig": {
36
36
  "access": "public"
37
37
  }
38
- }
38
+ }