@owney/sdk 0.7.3 → 0.7.4

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
@@ -1318,20 +1318,94 @@ var ZyfaiAgent = class {
1318
1318
  );
1319
1319
  }
1320
1320
  }
1321
+ /**
1322
+ * True when `smartWallet` is the backend-managed pool wallet Zyfai assigned
1323
+ * to this EOA — the "new wallet" kind that is predeployed on the chains it
1324
+ * was onboarded to. Legacy wallets (created before @zyfai/sdk 0.2.44) have no
1325
+ * pool record.
1326
+ *
1327
+ * A failed lookup returns false rather than throwing: misclassifying is
1328
+ * recoverable (ensureWalletDeployed tries the other deploy call), but
1329
+ * failing the deposit outright is not.
1330
+ */
1331
+ async isPredeployedPoolWallet(ownerAddress, smartWallet) {
1332
+ try {
1333
+ const byEoa = await this.sdk.getSmartWalletByEOA(ownerAddress);
1334
+ return typeof byEoa?.smartWallet === "string" && byEoa.smartWallet.toLowerCase() === smartWallet.toLowerCase();
1335
+ } catch (error) {
1336
+ console.warn(
1337
+ "[zyfai] getSmartWalletByEOA failed; assuming a legacy wallet:",
1338
+ error instanceof Error ? error.message : String(error)
1339
+ );
1340
+ return false;
1341
+ }
1342
+ }
1343
+ /**
1344
+ * Guarantee the user's Safe has code on `chainId` before anything transfers
1345
+ * funds into it, and return its address.
1346
+ *
1347
+ * Zyfai predeploys wallets created since @zyfai/sdk 0.2.44, but ONLY on the
1348
+ * chains they were onboarded to. Legacy wallets, and any chain a pool wallet
1349
+ * has not been onboarded to, are *counterfactual*: `getSmartWalletAddress`
1350
+ * returns a real deterministic address that holds no code yet. Depositing
1351
+ * there strands the funds until the Safe is deployed, and Owney's own sponsor
1352
+ * relayer refuses to broadcast to an address with no bytecode
1353
+ * (`to-address.guard-helper.ts`), so the deposit fails as an opaque 500.
1354
+ *
1355
+ * ROUT-320 removed the old deploySafe step believing every wallet was
1356
+ * predeployed from 0.2.44 on. Zyf later clarified that only NEW wallets are;
1357
+ * old ones still need the legacy flow. Hence the gate is on the per-chain
1358
+ * `isDeployed` flag rather than on the wallet's age — that covers both a
1359
+ * legacy wallet and a pool wallet on a fresh chain.
1360
+ */
1361
+ async ensureWalletDeployed(ownerAddress, chainId) {
1362
+ const wallet = await this.sdk.getSmartWalletAddress(ownerAddress, chainId);
1363
+ if (wallet.isDeployed) return wallet.address;
1364
+ const poolFirst = await this.isPredeployedPoolWallet(
1365
+ ownerAddress,
1366
+ wallet.address
1367
+ );
1368
+ const deployAsPool = () => this.sdk.deployOnChains([chainId]);
1369
+ const deployAsLegacy = () => (
1370
+ // `createSessionKey: false` — session keys are backend-owned since the
1371
+ // predeployed-pool rollout; asking for one here costs a signature prompt
1372
+ // and is rejected anyway.
1373
+ this.sdk.deploySafe(ownerAddress, chainId, "aggressive", false)
1374
+ );
1375
+ const [first, second] = poolFirst ? [deployAsPool, deployAsLegacy] : [deployAsLegacy, deployAsPool];
1376
+ try {
1377
+ await first();
1378
+ } catch (error) {
1379
+ console.warn(
1380
+ `[zyfai] ${poolFirst ? "deployOnChains" : "deploySafe"} failed on chain ${chainId}; trying the other deploy path:`,
1381
+ error instanceof Error ? error.message : String(error)
1382
+ );
1383
+ await second();
1384
+ }
1385
+ const redeployed = await this.sdk.getSmartWalletAddress(
1386
+ ownerAddress,
1387
+ chainId
1388
+ );
1389
+ if (!redeployed.isDeployed) {
1390
+ throw new OwneyError(
1391
+ "WALLET_NOT_DEPLOYED",
1392
+ `Smart wallet ${redeployed.address} is still not deployed on chain ${chainId}. Depositing would send funds to an address with no code.`,
1393
+ { chainId, smartWallet: redeployed.address },
1394
+ this.id
1395
+ );
1396
+ }
1397
+ return redeployed.address;
1398
+ }
1321
1399
  async deposit(state, chainId, amount, asset, depositCallback) {
1322
1400
  try {
1323
1401
  const validChainId = isValidChainId(chainId);
1324
1402
  await this.ensureConnected(state, validChainId);
1325
1403
  if (depositCallback) {
1326
- const wallet = await this.sdk.getSmartWalletAddress(
1404
+ const smartWallet = await this.ensureWalletDeployed(
1327
1405
  this.getAddress(),
1328
1406
  validChainId
1329
1407
  );
1330
- const txHash = await depositCallback(
1331
- wallet.address,
1332
- validChainId,
1333
- amount
1334
- );
1408
+ const txHash = await depositCallback(smartWallet, validChainId, amount);
1335
1409
  const tokenAddress = asset === "WETH" ? WETH_ADDRESS_BY_CHAIN[validChainId] : void 0;
1336
1410
  try {
1337
1411
  await (tokenAddress ? this.sdk.logDeposit(validChainId, txHash, amount, tokenAddress) : this.sdk.logDeposit(validChainId, txHash, amount));
@@ -1341,8 +1415,9 @@ var ZyfaiAgent = class {
1341
1415
  logError
1342
1416
  );
1343
1417
  }
1344
- return { txHash, smartWallet: wallet.address, amount };
1418
+ return { txHash, smartWallet, amount };
1345
1419
  }
1420
+ await this.ensureWalletDeployed(this.getAddress(), validChainId);
1346
1421
  const raw = await this.sdk.depositFunds(
1347
1422
  this.getAddress(),
1348
1423
  validChainId,
package/dist/index.d.cts CHANGED
@@ -609,7 +609,7 @@ declare class OwneySDK {
609
609
  getAllocationApy({ agentId, }?: AllocationApyOptions): Promise<OwneyAllocationApy>;
610
610
  }
611
611
 
612
- 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" | "DEPOSIT_INSUFFICIENT_BALANCE" | "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" | "PERMIT2_APPROVAL_REQUIRED" | "BALANCE_ALL_FAILED" | "ALLOCATION_ALL_FAILED" | "VALIDATION_INVALID_DAYS";
612
+ type OwneyErrorCode = "NOT_CONNECTED" | "NO_ACTIVE_CHAIN" | "WALLET_NO_ACCOUNTS" | "WALLET_ADDRESS_REQUIRED" | "WALLET_NOT_DEPLOYED" | "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" | "DEPOSIT_INSUFFICIENT_BALANCE" | "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" | "PERMIT2_APPROVAL_REQUIRED" | "BALANCE_ALL_FAILED" | "ALLOCATION_ALL_FAILED" | "VALIDATION_INVALID_DAYS";
613
613
  declare class OwneyError extends Error {
614
614
  readonly code: OwneyErrorCode;
615
615
  readonly details?: Record<string, unknown>;
package/dist/index.d.ts CHANGED
@@ -609,7 +609,7 @@ declare class OwneySDK {
609
609
  getAllocationApy({ agentId, }?: AllocationApyOptions): Promise<OwneyAllocationApy>;
610
610
  }
611
611
 
612
- 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" | "DEPOSIT_INSUFFICIENT_BALANCE" | "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" | "PERMIT2_APPROVAL_REQUIRED" | "BALANCE_ALL_FAILED" | "ALLOCATION_ALL_FAILED" | "VALIDATION_INVALID_DAYS";
612
+ type OwneyErrorCode = "NOT_CONNECTED" | "NO_ACTIVE_CHAIN" | "WALLET_NO_ACCOUNTS" | "WALLET_ADDRESS_REQUIRED" | "WALLET_NOT_DEPLOYED" | "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" | "DEPOSIT_INSUFFICIENT_BALANCE" | "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" | "PERMIT2_APPROVAL_REQUIRED" | "BALANCE_ALL_FAILED" | "ALLOCATION_ALL_FAILED" | "VALIDATION_INVALID_DAYS";
613
613
  declare class OwneyError extends Error {
614
614
  readonly code: OwneyErrorCode;
615
615
  readonly details?: Record<string, unknown>;
package/dist/index.js CHANGED
@@ -1285,20 +1285,94 @@ var ZyfaiAgent = class {
1285
1285
  );
1286
1286
  }
1287
1287
  }
1288
+ /**
1289
+ * True when `smartWallet` is the backend-managed pool wallet Zyfai assigned
1290
+ * to this EOA — the "new wallet" kind that is predeployed on the chains it
1291
+ * was onboarded to. Legacy wallets (created before @zyfai/sdk 0.2.44) have no
1292
+ * pool record.
1293
+ *
1294
+ * A failed lookup returns false rather than throwing: misclassifying is
1295
+ * recoverable (ensureWalletDeployed tries the other deploy call), but
1296
+ * failing the deposit outright is not.
1297
+ */
1298
+ async isPredeployedPoolWallet(ownerAddress, smartWallet) {
1299
+ try {
1300
+ const byEoa = await this.sdk.getSmartWalletByEOA(ownerAddress);
1301
+ return typeof byEoa?.smartWallet === "string" && byEoa.smartWallet.toLowerCase() === smartWallet.toLowerCase();
1302
+ } catch (error) {
1303
+ console.warn(
1304
+ "[zyfai] getSmartWalletByEOA failed; assuming a legacy wallet:",
1305
+ error instanceof Error ? error.message : String(error)
1306
+ );
1307
+ return false;
1308
+ }
1309
+ }
1310
+ /**
1311
+ * Guarantee the user's Safe has code on `chainId` before anything transfers
1312
+ * funds into it, and return its address.
1313
+ *
1314
+ * Zyfai predeploys wallets created since @zyfai/sdk 0.2.44, but ONLY on the
1315
+ * chains they were onboarded to. Legacy wallets, and any chain a pool wallet
1316
+ * has not been onboarded to, are *counterfactual*: `getSmartWalletAddress`
1317
+ * returns a real deterministic address that holds no code yet. Depositing
1318
+ * there strands the funds until the Safe is deployed, and Owney's own sponsor
1319
+ * relayer refuses to broadcast to an address with no bytecode
1320
+ * (`to-address.guard-helper.ts`), so the deposit fails as an opaque 500.
1321
+ *
1322
+ * ROUT-320 removed the old deploySafe step believing every wallet was
1323
+ * predeployed from 0.2.44 on. Zyf later clarified that only NEW wallets are;
1324
+ * old ones still need the legacy flow. Hence the gate is on the per-chain
1325
+ * `isDeployed` flag rather than on the wallet's age — that covers both a
1326
+ * legacy wallet and a pool wallet on a fresh chain.
1327
+ */
1328
+ async ensureWalletDeployed(ownerAddress, chainId) {
1329
+ const wallet = await this.sdk.getSmartWalletAddress(ownerAddress, chainId);
1330
+ if (wallet.isDeployed) return wallet.address;
1331
+ const poolFirst = await this.isPredeployedPoolWallet(
1332
+ ownerAddress,
1333
+ wallet.address
1334
+ );
1335
+ const deployAsPool = () => this.sdk.deployOnChains([chainId]);
1336
+ const deployAsLegacy = () => (
1337
+ // `createSessionKey: false` — session keys are backend-owned since the
1338
+ // predeployed-pool rollout; asking for one here costs a signature prompt
1339
+ // and is rejected anyway.
1340
+ this.sdk.deploySafe(ownerAddress, chainId, "aggressive", false)
1341
+ );
1342
+ const [first, second] = poolFirst ? [deployAsPool, deployAsLegacy] : [deployAsLegacy, deployAsPool];
1343
+ try {
1344
+ await first();
1345
+ } catch (error) {
1346
+ console.warn(
1347
+ `[zyfai] ${poolFirst ? "deployOnChains" : "deploySafe"} failed on chain ${chainId}; trying the other deploy path:`,
1348
+ error instanceof Error ? error.message : String(error)
1349
+ );
1350
+ await second();
1351
+ }
1352
+ const redeployed = await this.sdk.getSmartWalletAddress(
1353
+ ownerAddress,
1354
+ chainId
1355
+ );
1356
+ if (!redeployed.isDeployed) {
1357
+ throw new OwneyError(
1358
+ "WALLET_NOT_DEPLOYED",
1359
+ `Smart wallet ${redeployed.address} is still not deployed on chain ${chainId}. Depositing would send funds to an address with no code.`,
1360
+ { chainId, smartWallet: redeployed.address },
1361
+ this.id
1362
+ );
1363
+ }
1364
+ return redeployed.address;
1365
+ }
1288
1366
  async deposit(state, chainId, amount, asset, depositCallback) {
1289
1367
  try {
1290
1368
  const validChainId = isValidChainId(chainId);
1291
1369
  await this.ensureConnected(state, validChainId);
1292
1370
  if (depositCallback) {
1293
- const wallet = await this.sdk.getSmartWalletAddress(
1371
+ const smartWallet = await this.ensureWalletDeployed(
1294
1372
  this.getAddress(),
1295
1373
  validChainId
1296
1374
  );
1297
- const txHash = await depositCallback(
1298
- wallet.address,
1299
- validChainId,
1300
- amount
1301
- );
1375
+ const txHash = await depositCallback(smartWallet, validChainId, amount);
1302
1376
  const tokenAddress = asset === "WETH" ? WETH_ADDRESS_BY_CHAIN[validChainId] : void 0;
1303
1377
  try {
1304
1378
  await (tokenAddress ? this.sdk.logDeposit(validChainId, txHash, amount, tokenAddress) : this.sdk.logDeposit(validChainId, txHash, amount));
@@ -1308,8 +1382,9 @@ var ZyfaiAgent = class {
1308
1382
  logError
1309
1383
  );
1310
1384
  }
1311
- return { txHash, smartWallet: wallet.address, amount };
1385
+ return { txHash, smartWallet, amount };
1312
1386
  }
1387
+ await this.ensureWalletDeployed(this.getAddress(), validChainId);
1313
1388
  const raw = await this.sdk.depositFunds(
1314
1389
  this.getAddress(),
1315
1390
  validChainId,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@owney/sdk",
3
- "version": "0.7.3",
3
+ "version": "0.7.4",
4
4
  "type": "module",
5
5
  "main": "dist/index.cjs",
6
6
  "module": "dist/index.js",