@owney/sdk 0.7.26-beta.7 → 0.7.26-beta.8

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
@@ -5199,6 +5199,64 @@ var OwneySDK = class {
5199
5199
  * the deposit's own check is the authority and refusing to even attempt
5200
5200
  * would strand funds we might have been able to move.
5201
5201
  */
5202
+ /** ERC20 balance of the connected wallet, read through the wallet's own node. */
5203
+ async readTokenBalance(chainId, token) {
5204
+ const state = this.requireState();
5205
+ return readErc20Balance(
5206
+ (0, import_viem9.createPublicClient)({
5207
+ chain: swapChain(chainId),
5208
+ transport: (0, import_viem9.custom)(this.requireConnectedProvider())
5209
+ }),
5210
+ token,
5211
+ state.walletAddress
5212
+ );
5213
+ }
5214
+ /** How much of `token` the wallet has already approved Permit2 to move. */
5215
+ async readTokenPermit2Allowance(chainId, token) {
5216
+ const state = this.requireState();
5217
+ return readPermit2Allowance(
5218
+ (0, import_viem9.createPublicClient)({
5219
+ chain: swapChain(chainId),
5220
+ transport: (0, import_viem9.custom)(this.requireConnectedProvider())
5221
+ }),
5222
+ token,
5223
+ state.walletAddress
5224
+ );
5225
+ }
5226
+ /**
5227
+ * How much of a landed swap to actually deposit.
5228
+ *
5229
+ * The swap reports what ARRIVED, and the deposit used to be handed that
5230
+ * figure directly. It is the entire arrival, so there is no slack: anything
5231
+ * that spends the target asset between the two fails the deposit outright.
5232
+ *
5233
+ * Something does. A first WETH deposit needs a one-time Permit2 approval,
5234
+ * and that approval is a transaction. A wallet holding no native gas token -
5235
+ * the normal state of someone who just swapped everything INTO WETH - pays
5236
+ * for it out of the WETH. The deposit then asked for ~2e12 wei more than was
5237
+ * left and refused with DEPOSIT_INSUFFICIENT_BALANCE, under a wrapper saying
5238
+ * the funds were safe but unadded (ROUT-242).
5239
+ *
5240
+ * So the approval happens here, before the amount is settled, and the amount
5241
+ * comes from a read taken after it. Two things this deliberately is not:
5242
+ *
5243
+ * - It is not a balance sweep. `received` is a DELTA over the pre-swap
5244
+ * balance, so a wallet already holding WETH reads far above it; depositing
5245
+ * the balance would move funds the user never offered. The arrival is the
5246
+ * ceiling and the balance is only ever allowed to lower it.
5247
+ * - It does not touch USDC, which moves on signed typed data and so spends
5248
+ * nothing of the user's in between, nor a paymaster-configured client,
5249
+ * where the sponsor covers the transfer and Permit2 never applies.
5250
+ */
5251
+ async settleSwapDepositAmount(chainId, token, symbol, received) {
5252
+ if (symbol !== "WETH" || this.paymasterServiceUrl) {
5253
+ return received.toString();
5254
+ }
5255
+ const allowance = await this.readTokenPermit2Allowance(chainId, token);
5256
+ if (allowance < received) await this.approvePermit2();
5257
+ const balance = await this.readTokenBalance(chainId, token);
5258
+ return (balance < received ? balance : received).toString();
5259
+ }
5202
5260
  async walletSeesBalance(chainId, token, amount) {
5203
5261
  const provider = this.requireConnectedProvider();
5204
5262
  const state = this.requireState();
@@ -5427,7 +5485,7 @@ var OwneySDK = class {
5427
5485
  */
5428
5486
  async getWalletBalances(chainIds) {
5429
5487
  const state = this.requireState();
5430
- const chains = chainIds ?? SUPPORTED_CHAIN_IDS;
5488
+ const chains = chainIds ?? SWAP_CHAIN_IDS;
5431
5489
  const failedChainIds = [];
5432
5490
  const results = await Promise.all(
5433
5491
  chains.map(async (chainId) => {
@@ -5533,12 +5591,18 @@ var OwneySDK = class {
5533
5591
  quote.dst.address,
5534
5592
  BigInt(swap.received)
5535
5593
  );
5594
+ const amount = await this.settleSwapDepositAmount(
5595
+ quote.dst.chainId,
5596
+ quote.dst.address,
5597
+ options.to.symbol,
5598
+ BigInt(swap.received)
5599
+ );
5536
5600
  const deposit = await this.deposit({
5537
- amount: swap.received,
5601
+ amount,
5538
5602
  asset: options.to.symbol,
5539
5603
  ...options.agentId ? { agentId: options.agentId } : {}
5540
5604
  });
5541
- return { swap, deposit };
5605
+ return { swap, deposit, deposited: amount };
5542
5606
  } catch (error) {
5543
5607
  const pending = {
5544
5608
  id: `${quote.dst.chainId}-${options.to.symbol}-${Date.now()}`,
package/dist/index.d.cts CHANGED
@@ -1129,6 +1129,36 @@ declare class OwneySDK {
1129
1129
  * the deposit's own check is the authority and refusing to even attempt
1130
1130
  * would strand funds we might have been able to move.
1131
1131
  */
1132
+ /** ERC20 balance of the connected wallet, read through the wallet's own node. */
1133
+ private readTokenBalance;
1134
+ /** How much of `token` the wallet has already approved Permit2 to move. */
1135
+ private readTokenPermit2Allowance;
1136
+ /**
1137
+ * How much of a landed swap to actually deposit.
1138
+ *
1139
+ * The swap reports what ARRIVED, and the deposit used to be handed that
1140
+ * figure directly. It is the entire arrival, so there is no slack: anything
1141
+ * that spends the target asset between the two fails the deposit outright.
1142
+ *
1143
+ * Something does. A first WETH deposit needs a one-time Permit2 approval,
1144
+ * and that approval is a transaction. A wallet holding no native gas token -
1145
+ * the normal state of someone who just swapped everything INTO WETH - pays
1146
+ * for it out of the WETH. The deposit then asked for ~2e12 wei more than was
1147
+ * left and refused with DEPOSIT_INSUFFICIENT_BALANCE, under a wrapper saying
1148
+ * the funds were safe but unadded (ROUT-242).
1149
+ *
1150
+ * So the approval happens here, before the amount is settled, and the amount
1151
+ * comes from a read taken after it. Two things this deliberately is not:
1152
+ *
1153
+ * - It is not a balance sweep. `received` is a DELTA over the pre-swap
1154
+ * balance, so a wallet already holding WETH reads far above it; depositing
1155
+ * the balance would move funds the user never offered. The arrival is the
1156
+ * ceiling and the balance is only ever allowed to lower it.
1157
+ * - It does not touch USDC, which moves on signed typed data and so spends
1158
+ * nothing of the user's in between, nor a paymaster-configured client,
1159
+ * where the sponsor covers the transfer and Permit2 never applies.
1160
+ */
1161
+ private settleSwapDepositAmount;
1132
1162
  private walletSeesBalance;
1133
1163
  /**
1134
1164
  * Runs a quoted swap. A named seam rather than an inline `executeSwap` call
@@ -1328,6 +1358,12 @@ declare class OwneySDK {
1328
1358
  txHash?: string;
1329
1359
  };
1330
1360
  deposit: OwneyDepositResult | OwneyMultiDepositResult;
1361
+ /**
1362
+ * What was actually deposited, which is not always what the swap
1363
+ * delivered - see `settleSwapDepositAmount`. Callers seeding a headline
1364
+ * want this one; `swap.received` stays what it says it is.
1365
+ */
1366
+ deposited: string;
1331
1367
  }>;
1332
1368
  /**
1333
1369
  * Withdraw from an agent and swap the proceeds into whatever the user wants
package/dist/index.d.ts CHANGED
@@ -1129,6 +1129,36 @@ declare class OwneySDK {
1129
1129
  * the deposit's own check is the authority and refusing to even attempt
1130
1130
  * would strand funds we might have been able to move.
1131
1131
  */
1132
+ /** ERC20 balance of the connected wallet, read through the wallet's own node. */
1133
+ private readTokenBalance;
1134
+ /** How much of `token` the wallet has already approved Permit2 to move. */
1135
+ private readTokenPermit2Allowance;
1136
+ /**
1137
+ * How much of a landed swap to actually deposit.
1138
+ *
1139
+ * The swap reports what ARRIVED, and the deposit used to be handed that
1140
+ * figure directly. It is the entire arrival, so there is no slack: anything
1141
+ * that spends the target asset between the two fails the deposit outright.
1142
+ *
1143
+ * Something does. A first WETH deposit needs a one-time Permit2 approval,
1144
+ * and that approval is a transaction. A wallet holding no native gas token -
1145
+ * the normal state of someone who just swapped everything INTO WETH - pays
1146
+ * for it out of the WETH. The deposit then asked for ~2e12 wei more than was
1147
+ * left and refused with DEPOSIT_INSUFFICIENT_BALANCE, under a wrapper saying
1148
+ * the funds were safe but unadded (ROUT-242).
1149
+ *
1150
+ * So the approval happens here, before the amount is settled, and the amount
1151
+ * comes from a read taken after it. Two things this deliberately is not:
1152
+ *
1153
+ * - It is not a balance sweep. `received` is a DELTA over the pre-swap
1154
+ * balance, so a wallet already holding WETH reads far above it; depositing
1155
+ * the balance would move funds the user never offered. The arrival is the
1156
+ * ceiling and the balance is only ever allowed to lower it.
1157
+ * - It does not touch USDC, which moves on signed typed data and so spends
1158
+ * nothing of the user's in between, nor a paymaster-configured client,
1159
+ * where the sponsor covers the transfer and Permit2 never applies.
1160
+ */
1161
+ private settleSwapDepositAmount;
1132
1162
  private walletSeesBalance;
1133
1163
  /**
1134
1164
  * Runs a quoted swap. A named seam rather than an inline `executeSwap` call
@@ -1328,6 +1358,12 @@ declare class OwneySDK {
1328
1358
  txHash?: string;
1329
1359
  };
1330
1360
  deposit: OwneyDepositResult | OwneyMultiDepositResult;
1361
+ /**
1362
+ * What was actually deposited, which is not always what the swap
1363
+ * delivered - see `settleSwapDepositAmount`. Callers seeding a headline
1364
+ * want this one; `swap.received` stays what it says it is.
1365
+ */
1366
+ deposited: string;
1331
1367
  }>;
1332
1368
  /**
1333
1369
  * Withdraw from an agent and swap the proceeds into whatever the user wants
package/dist/index.js CHANGED
@@ -5180,6 +5180,64 @@ var OwneySDK = class {
5180
5180
  * the deposit's own check is the authority and refusing to even attempt
5181
5181
  * would strand funds we might have been able to move.
5182
5182
  */
5183
+ /** ERC20 balance of the connected wallet, read through the wallet's own node. */
5184
+ async readTokenBalance(chainId, token) {
5185
+ const state = this.requireState();
5186
+ return readErc20Balance(
5187
+ createPublicClient2({
5188
+ chain: swapChain(chainId),
5189
+ transport: custom(this.requireConnectedProvider())
5190
+ }),
5191
+ token,
5192
+ state.walletAddress
5193
+ );
5194
+ }
5195
+ /** How much of `token` the wallet has already approved Permit2 to move. */
5196
+ async readTokenPermit2Allowance(chainId, token) {
5197
+ const state = this.requireState();
5198
+ return readPermit2Allowance(
5199
+ createPublicClient2({
5200
+ chain: swapChain(chainId),
5201
+ transport: custom(this.requireConnectedProvider())
5202
+ }),
5203
+ token,
5204
+ state.walletAddress
5205
+ );
5206
+ }
5207
+ /**
5208
+ * How much of a landed swap to actually deposit.
5209
+ *
5210
+ * The swap reports what ARRIVED, and the deposit used to be handed that
5211
+ * figure directly. It is the entire arrival, so there is no slack: anything
5212
+ * that spends the target asset between the two fails the deposit outright.
5213
+ *
5214
+ * Something does. A first WETH deposit needs a one-time Permit2 approval,
5215
+ * and that approval is a transaction. A wallet holding no native gas token -
5216
+ * the normal state of someone who just swapped everything INTO WETH - pays
5217
+ * for it out of the WETH. The deposit then asked for ~2e12 wei more than was
5218
+ * left and refused with DEPOSIT_INSUFFICIENT_BALANCE, under a wrapper saying
5219
+ * the funds were safe but unadded (ROUT-242).
5220
+ *
5221
+ * So the approval happens here, before the amount is settled, and the amount
5222
+ * comes from a read taken after it. Two things this deliberately is not:
5223
+ *
5224
+ * - It is not a balance sweep. `received` is a DELTA over the pre-swap
5225
+ * balance, so a wallet already holding WETH reads far above it; depositing
5226
+ * the balance would move funds the user never offered. The arrival is the
5227
+ * ceiling and the balance is only ever allowed to lower it.
5228
+ * - It does not touch USDC, which moves on signed typed data and so spends
5229
+ * nothing of the user's in between, nor a paymaster-configured client,
5230
+ * where the sponsor covers the transfer and Permit2 never applies.
5231
+ */
5232
+ async settleSwapDepositAmount(chainId, token, symbol, received) {
5233
+ if (symbol !== "WETH" || this.paymasterServiceUrl) {
5234
+ return received.toString();
5235
+ }
5236
+ const allowance = await this.readTokenPermit2Allowance(chainId, token);
5237
+ if (allowance < received) await this.approvePermit2();
5238
+ const balance = await this.readTokenBalance(chainId, token);
5239
+ return (balance < received ? balance : received).toString();
5240
+ }
5183
5241
  async walletSeesBalance(chainId, token, amount) {
5184
5242
  const provider = this.requireConnectedProvider();
5185
5243
  const state = this.requireState();
@@ -5408,7 +5466,7 @@ var OwneySDK = class {
5408
5466
  */
5409
5467
  async getWalletBalances(chainIds) {
5410
5468
  const state = this.requireState();
5411
- const chains = chainIds ?? SUPPORTED_CHAIN_IDS;
5469
+ const chains = chainIds ?? SWAP_CHAIN_IDS;
5412
5470
  const failedChainIds = [];
5413
5471
  const results = await Promise.all(
5414
5472
  chains.map(async (chainId) => {
@@ -5514,12 +5572,18 @@ var OwneySDK = class {
5514
5572
  quote.dst.address,
5515
5573
  BigInt(swap.received)
5516
5574
  );
5575
+ const amount = await this.settleSwapDepositAmount(
5576
+ quote.dst.chainId,
5577
+ quote.dst.address,
5578
+ options.to.symbol,
5579
+ BigInt(swap.received)
5580
+ );
5517
5581
  const deposit = await this.deposit({
5518
- amount: swap.received,
5582
+ amount,
5519
5583
  asset: options.to.symbol,
5520
5584
  ...options.agentId ? { agentId: options.agentId } : {}
5521
5585
  });
5522
- return { swap, deposit };
5586
+ return { swap, deposit, deposited: amount };
5523
5587
  } catch (error) {
5524
5588
  const pending = {
5525
5589
  id: `${quote.dst.chainId}-${options.to.symbol}-${Date.now()}`,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@owney/sdk",
3
- "version": "0.7.26-beta.7",
3
+ "version": "0.7.26-beta.8",
4
4
  "type": "module",
5
5
  "main": "dist/index.cjs",
6
6
  "module": "dist/index.js",