@stablechain/sdk 1.0.7 → 1.0.9

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.d.cts CHANGED
@@ -222,17 +222,23 @@ interface BridgeGasEstimate {
222
222
  interface BridgeTimeEstimate {
223
223
  /** Best available estimate, in seconds — prefer this for display */
224
224
  seconds: number;
225
- /** Which input produced `seconds` — see {@link BridgeTimeEstimate.observedSeconds} */
226
- source: "observed" | "formula";
227
225
  /**
228
- * Median delivery time of recent delivered messages on this exact pathway,
229
- * from LayerZero Scan. More trustworthy than `formulaSeconds` — notably on
230
- * rollup sources, where DVNs wait for L1 finality rather than raw block count.
226
+ * Which input produced `seconds`. `"formula"` normally; `"floor"` when the
227
+ * source chain's measured minimum exceeded it (Ethereum, Arbitrum, Polygon,
228
+ * Bera, Flare); `"observed"` only when the pathway's ULN config could not be read.
229
+ */
230
+ source: "formula" | "floor" | "observed";
231
+ /**
232
+ * Median delivery time of recent delivered messages on this exact pathway, from
233
+ * LayerZero Scan. Reported for comparison but no longer preferred: a 50-message
234
+ * window can reach back months, so it answers from a ULN config the pathway has
235
+ * since moved off.
231
236
  */
232
237
  observedSeconds?: number;
233
238
  /**
234
239
  * LayerZero's documented estimate:
235
- * `srcBlockTime × confirmations + dstBlockTime × (2 + dvnCount)`.
240
+ * `srcBlockTime × confirmations + dstBlockTime × (2 + dvnCount)`. What `seconds`
241
+ * reports unless the source chain's measured floor is higher.
236
242
  */
237
243
  formulaSeconds?: number;
238
244
  /** Source-chain block confirmations the DVNs wait for before attesting */
@@ -257,12 +263,12 @@ interface BridgeStatus {
257
263
  /**
258
264
  * Bridge route selection:
259
265
  * - `"oft"` — force the native LayerZero OFT path for whichever asset the token
260
- * addresses name, USDT0 or XAUt0 (no protocol fee, just gas + LZ messaging fee;
266
+ * addresses name, USDT0, XAUt0 or PYUSD (no protocol fee, just gas + LZ messaging fee;
261
267
  * slower). Throws if the chain pair has no adapter for that asset.
262
268
  * - `"usdt0"` — deprecated alias for `"oft"`, kept for compatibility. It does not
263
269
  * restrict the route to USDT0; the token addresses decide the asset.
264
270
  * - `"lifi"` — force the LI.FI aggregator path (fast, charges a fee).
265
- * - `"auto"` — use the native OFT mesh (USDT0 or XAUt0) when both chains deploy
271
+ * - `"auto"` — use the native OFT mesh (USDT0, XAUt0 or PYUSD) when both chains deploy
266
272
  * the requested asset and the token addresses match, else LI.FI.
267
273
  * This is the default.
268
274
  */
@@ -367,7 +373,7 @@ interface BridgeCalldata {
367
373
  /** The source chain every step must be sent on */
368
374
  chainId: number;
369
375
  /** Which OFT mesh this send moves through */
370
- asset: "usdt0" | "xaut0";
376
+ asset: "usdt0" | "xaut0" | "pyusd";
371
377
  /** The quote these steps were built from, whether supplied or freshly read */
372
378
  quote: BridgeQuote;
373
379
  /**
@@ -705,7 +711,7 @@ interface ChainConfig {
705
711
  declare const CHAIN_CONFIGS: Partial<Record<Chain, ChainConfig>>;
706
712
 
707
713
  /** An asset with its own LayerZero OFT mesh. Each has separate adapters per chain. */
708
- type BridgeAsset = "usdt0" | "xaut0";
714
+ type BridgeAsset = "usdt0" | "xaut0" | "pyusd";
709
715
  /** One asset's deployment on one chain. */
710
716
  interface BridgeTokenConfig {
711
717
  /** The ERC-20 a holder owns — what gets debited, and approved when required */
@@ -722,12 +728,18 @@ interface BridgeTokenConfig {
722
728
  approvalRequired?: boolean;
723
729
  /** False when the adapter exists but has no outbound send pathways configured */
724
730
  lzOutbound?: boolean;
731
+ /**
732
+ * Overrides the chain's {@link BridgeChainConfig.minDeliverySec} for sends of
733
+ * this asset. The chain's floor was measured on one asset's pathways; another
734
+ * asset's DVNs may not share its wait (0 means no floor).
735
+ */
736
+ minDeliverySec?: number;
725
737
  }
726
738
  interface BridgeChainConfig extends ChainConfig {
727
739
  lzEid: number;
728
740
  /**
729
- * Which OFT assets this chain can bridge. A chain may carry one and not the
730
- * other — BSC has XAUt0 but no USDT0 deployment.
741
+ * Which OFT assets this chain can bridge. A chain may carry some and not the
742
+ * others — BSC has XAUt0 but no USDT0 deployment.
731
743
  */
732
744
  tokens: Partial<Record<BridgeAsset, BridgeTokenConfig>>;
733
745
  /**
@@ -743,6 +755,26 @@ interface BridgeChainConfig extends ChainConfig {
743
755
  * requirement into a wall-clock estimate. Measured from mainnet, 2026-07-30.
744
756
  */
745
757
  blockTimeSec?: number;
758
+ /**
759
+ * Floor on delivery time, in seconds, for sends *from* this chain — set only
760
+ * where the confirmation count is demonstrably not the whole wait.
761
+ *
762
+ * Two things sit outside the formula: DVN attestation and destination execution,
763
+ * a roughly fixed overhead, and on Ethereum and Arbitrum a hold until the send
764
+ * finalizes on the beacon chain. Where confirmations are high the overhead is lost
765
+ * in the rounding — Optimism's 1000 and X Layer's 9000 both land within 0.5% of
766
+ * observed. Where they are low it dominates: Arbitrum's 60 confirmations compute
767
+ * to ~19s against a real ~18min, Ethereum's 65 to ~13min against ~17min, Polygon's
768
+ * 32 to ~52s against a real ~70s, Flare's 500 to ~9min against a real ~10min.
769
+ *
770
+ * Each figure is taken from deliveries LayerZero Scan held on 2026-08-27, no older
771
+ * than 45 days — the ceiling of that spread for the two finality-bound chains, so
772
+ * the estimate errs long, and the median for the rest. Flare's is a median across
773
+ * its destinations rather than one pathway's, since the hub pathway alone had only
774
+ * six recent sends to go on; those settled at ~9m30s and the busier pathways to
775
+ * Ethereum, Arbitrum, Plasma, Polygon and Optimism between ~9m20s and ~10m10s.
776
+ */
777
+ minDeliverySec?: number;
746
778
  }
747
779
  declare const BRIDGE_CHAIN_CONFIGS: Partial<Record<Chain, BridgeChainConfig>>;
748
780
  /**
@@ -916,6 +948,12 @@ declare function clearBridgeEstimateCache(): void;
916
948
  declare function buildLzOptions(gasLimit?: bigint, nativeDrop?: bigint, dropReceiver?: Address): Hex;
917
949
 
918
950
  declare const STABLE_USDT_ADDRESS: Address;
951
+ /**
952
+ * PayPal USD on Stable mainnet — 6 decimals, ERC-3009 capable. Its EIP-712 domain is
953
+ * `{ name: "PayPal USD", version: "1" }`, which the ERC-3009 actions resolve on their
954
+ * own (verified against the contract's DOMAIN_SEPARATOR, 2026-10-20).
955
+ */
956
+ declare const STABLE_PYUSD_ADDRESS: Address;
919
957
  declare const STABLE_VAULT_ADDRESS: Address;
920
958
 
921
959
  declare class StableError extends BaseError {
@@ -975,4 +1013,4 @@ declare class StableBulkError extends StableError {
975
1013
  });
976
1014
  }
977
1015
 
978
- export { BRIDGE_CHAIN_CONFIGS, type BridgeAsset, type BridgeCalldata, type BridgeCalldataStep, type BridgeChainConfig, type BridgeDeliveryState, type BridgeGasEstimate, type BridgeOftFee, type BridgeOftQuote, type BridgeParams, type BridgeQuote, type BridgeRoute, type BridgeStatus, type BridgeTimeEstimate, type BridgeTokenConfig, type BulkDepositOptions, type BulkEarnResult, type BulkEarnResultItem, type BulkWithdrawOptions, CHAIN_CONFIGS, Chain, type ChainConfig, type EarnConfig, type EarnDepositCalldata, type EarnDepositParams, type EarnRedeemParams, type EarnResult, type EarnWithdrawCalldata, type EarnWithdrawParams, type ForceDeallocation, type ForceRedeemParams, type ForceWithdrawParams, type MerklClaimCalldata, type MerklClaimResult, type MerklReward, type MerklRewardToken, type MerklRewardsResult, Network, OFT_ADAPTER_ABI, type OperationResult, type PrepareBridgeParams, STABLE_USDT_ADDRESS, STABLE_VAULT_ADDRESS, StableBulkError, type StableClient, type StableConfig, StableError, StableNetworkError, StableQuoteError, type StableReader, type StableReaderConfig, StableTransactionError, StableValidationError, type SwapParams, type SwapQuote, type TransferParams, type VaultPosition, type VaultYield, type VaultYieldReward, type WithdrawStatus, type YieldPreview, bridgeAssetFor, buildLzOptions, clearBridgeEstimateCache, createStable, createStableReader, erc3009Actions };
1016
+ export { BRIDGE_CHAIN_CONFIGS, type BridgeAsset, type BridgeCalldata, type BridgeCalldataStep, type BridgeChainConfig, type BridgeDeliveryState, type BridgeGasEstimate, type BridgeOftFee, type BridgeOftQuote, type BridgeParams, type BridgeQuote, type BridgeRoute, type BridgeStatus, type BridgeTimeEstimate, type BridgeTokenConfig, type BulkDepositOptions, type BulkEarnResult, type BulkEarnResultItem, type BulkWithdrawOptions, CHAIN_CONFIGS, Chain, type ChainConfig, type EarnConfig, type EarnDepositCalldata, type EarnDepositParams, type EarnRedeemParams, type EarnResult, type EarnWithdrawCalldata, type EarnWithdrawParams, type ForceDeallocation, type ForceRedeemParams, type ForceWithdrawParams, type MerklClaimCalldata, type MerklClaimResult, type MerklReward, type MerklRewardToken, type MerklRewardsResult, Network, OFT_ADAPTER_ABI, type OperationResult, type PrepareBridgeParams, STABLE_PYUSD_ADDRESS, STABLE_USDT_ADDRESS, STABLE_VAULT_ADDRESS, StableBulkError, type StableClient, type StableConfig, StableError, StableNetworkError, StableQuoteError, type StableReader, type StableReaderConfig, StableTransactionError, StableValidationError, type SwapParams, type SwapQuote, type TransferParams, type VaultPosition, type VaultYield, type VaultYieldReward, type WithdrawStatus, type YieldPreview, bridgeAssetFor, buildLzOptions, clearBridgeEstimateCache, createStable, createStableReader, erc3009Actions };
package/dist/index.d.ts CHANGED
@@ -222,17 +222,23 @@ interface BridgeGasEstimate {
222
222
  interface BridgeTimeEstimate {
223
223
  /** Best available estimate, in seconds — prefer this for display */
224
224
  seconds: number;
225
- /** Which input produced `seconds` — see {@link BridgeTimeEstimate.observedSeconds} */
226
- source: "observed" | "formula";
227
225
  /**
228
- * Median delivery time of recent delivered messages on this exact pathway,
229
- * from LayerZero Scan. More trustworthy than `formulaSeconds` — notably on
230
- * rollup sources, where DVNs wait for L1 finality rather than raw block count.
226
+ * Which input produced `seconds`. `"formula"` normally; `"floor"` when the
227
+ * source chain's measured minimum exceeded it (Ethereum, Arbitrum, Polygon,
228
+ * Bera, Flare); `"observed"` only when the pathway's ULN config could not be read.
229
+ */
230
+ source: "formula" | "floor" | "observed";
231
+ /**
232
+ * Median delivery time of recent delivered messages on this exact pathway, from
233
+ * LayerZero Scan. Reported for comparison but no longer preferred: a 50-message
234
+ * window can reach back months, so it answers from a ULN config the pathway has
235
+ * since moved off.
231
236
  */
232
237
  observedSeconds?: number;
233
238
  /**
234
239
  * LayerZero's documented estimate:
235
- * `srcBlockTime × confirmations + dstBlockTime × (2 + dvnCount)`.
240
+ * `srcBlockTime × confirmations + dstBlockTime × (2 + dvnCount)`. What `seconds`
241
+ * reports unless the source chain's measured floor is higher.
236
242
  */
237
243
  formulaSeconds?: number;
238
244
  /** Source-chain block confirmations the DVNs wait for before attesting */
@@ -257,12 +263,12 @@ interface BridgeStatus {
257
263
  /**
258
264
  * Bridge route selection:
259
265
  * - `"oft"` — force the native LayerZero OFT path for whichever asset the token
260
- * addresses name, USDT0 or XAUt0 (no protocol fee, just gas + LZ messaging fee;
266
+ * addresses name, USDT0, XAUt0 or PYUSD (no protocol fee, just gas + LZ messaging fee;
261
267
  * slower). Throws if the chain pair has no adapter for that asset.
262
268
  * - `"usdt0"` — deprecated alias for `"oft"`, kept for compatibility. It does not
263
269
  * restrict the route to USDT0; the token addresses decide the asset.
264
270
  * - `"lifi"` — force the LI.FI aggregator path (fast, charges a fee).
265
- * - `"auto"` — use the native OFT mesh (USDT0 or XAUt0) when both chains deploy
271
+ * - `"auto"` — use the native OFT mesh (USDT0, XAUt0 or PYUSD) when both chains deploy
266
272
  * the requested asset and the token addresses match, else LI.FI.
267
273
  * This is the default.
268
274
  */
@@ -367,7 +373,7 @@ interface BridgeCalldata {
367
373
  /** The source chain every step must be sent on */
368
374
  chainId: number;
369
375
  /** Which OFT mesh this send moves through */
370
- asset: "usdt0" | "xaut0";
376
+ asset: "usdt0" | "xaut0" | "pyusd";
371
377
  /** The quote these steps were built from, whether supplied or freshly read */
372
378
  quote: BridgeQuote;
373
379
  /**
@@ -705,7 +711,7 @@ interface ChainConfig {
705
711
  declare const CHAIN_CONFIGS: Partial<Record<Chain, ChainConfig>>;
706
712
 
707
713
  /** An asset with its own LayerZero OFT mesh. Each has separate adapters per chain. */
708
- type BridgeAsset = "usdt0" | "xaut0";
714
+ type BridgeAsset = "usdt0" | "xaut0" | "pyusd";
709
715
  /** One asset's deployment on one chain. */
710
716
  interface BridgeTokenConfig {
711
717
  /** The ERC-20 a holder owns — what gets debited, and approved when required */
@@ -722,12 +728,18 @@ interface BridgeTokenConfig {
722
728
  approvalRequired?: boolean;
723
729
  /** False when the adapter exists but has no outbound send pathways configured */
724
730
  lzOutbound?: boolean;
731
+ /**
732
+ * Overrides the chain's {@link BridgeChainConfig.minDeliverySec} for sends of
733
+ * this asset. The chain's floor was measured on one asset's pathways; another
734
+ * asset's DVNs may not share its wait (0 means no floor).
735
+ */
736
+ minDeliverySec?: number;
725
737
  }
726
738
  interface BridgeChainConfig extends ChainConfig {
727
739
  lzEid: number;
728
740
  /**
729
- * Which OFT assets this chain can bridge. A chain may carry one and not the
730
- * other — BSC has XAUt0 but no USDT0 deployment.
741
+ * Which OFT assets this chain can bridge. A chain may carry some and not the
742
+ * others — BSC has XAUt0 but no USDT0 deployment.
731
743
  */
732
744
  tokens: Partial<Record<BridgeAsset, BridgeTokenConfig>>;
733
745
  /**
@@ -743,6 +755,26 @@ interface BridgeChainConfig extends ChainConfig {
743
755
  * requirement into a wall-clock estimate. Measured from mainnet, 2026-07-30.
744
756
  */
745
757
  blockTimeSec?: number;
758
+ /**
759
+ * Floor on delivery time, in seconds, for sends *from* this chain — set only
760
+ * where the confirmation count is demonstrably not the whole wait.
761
+ *
762
+ * Two things sit outside the formula: DVN attestation and destination execution,
763
+ * a roughly fixed overhead, and on Ethereum and Arbitrum a hold until the send
764
+ * finalizes on the beacon chain. Where confirmations are high the overhead is lost
765
+ * in the rounding — Optimism's 1000 and X Layer's 9000 both land within 0.5% of
766
+ * observed. Where they are low it dominates: Arbitrum's 60 confirmations compute
767
+ * to ~19s against a real ~18min, Ethereum's 65 to ~13min against ~17min, Polygon's
768
+ * 32 to ~52s against a real ~70s, Flare's 500 to ~9min against a real ~10min.
769
+ *
770
+ * Each figure is taken from deliveries LayerZero Scan held on 2026-08-27, no older
771
+ * than 45 days — the ceiling of that spread for the two finality-bound chains, so
772
+ * the estimate errs long, and the median for the rest. Flare's is a median across
773
+ * its destinations rather than one pathway's, since the hub pathway alone had only
774
+ * six recent sends to go on; those settled at ~9m30s and the busier pathways to
775
+ * Ethereum, Arbitrum, Plasma, Polygon and Optimism between ~9m20s and ~10m10s.
776
+ */
777
+ minDeliverySec?: number;
746
778
  }
747
779
  declare const BRIDGE_CHAIN_CONFIGS: Partial<Record<Chain, BridgeChainConfig>>;
748
780
  /**
@@ -916,6 +948,12 @@ declare function clearBridgeEstimateCache(): void;
916
948
  declare function buildLzOptions(gasLimit?: bigint, nativeDrop?: bigint, dropReceiver?: Address): Hex;
917
949
 
918
950
  declare const STABLE_USDT_ADDRESS: Address;
951
+ /**
952
+ * PayPal USD on Stable mainnet — 6 decimals, ERC-3009 capable. Its EIP-712 domain is
953
+ * `{ name: "PayPal USD", version: "1" }`, which the ERC-3009 actions resolve on their
954
+ * own (verified against the contract's DOMAIN_SEPARATOR, 2026-10-20).
955
+ */
956
+ declare const STABLE_PYUSD_ADDRESS: Address;
919
957
  declare const STABLE_VAULT_ADDRESS: Address;
920
958
 
921
959
  declare class StableError extends BaseError {
@@ -975,4 +1013,4 @@ declare class StableBulkError extends StableError {
975
1013
  });
976
1014
  }
977
1015
 
978
- export { BRIDGE_CHAIN_CONFIGS, type BridgeAsset, type BridgeCalldata, type BridgeCalldataStep, type BridgeChainConfig, type BridgeDeliveryState, type BridgeGasEstimate, type BridgeOftFee, type BridgeOftQuote, type BridgeParams, type BridgeQuote, type BridgeRoute, type BridgeStatus, type BridgeTimeEstimate, type BridgeTokenConfig, type BulkDepositOptions, type BulkEarnResult, type BulkEarnResultItem, type BulkWithdrawOptions, CHAIN_CONFIGS, Chain, type ChainConfig, type EarnConfig, type EarnDepositCalldata, type EarnDepositParams, type EarnRedeemParams, type EarnResult, type EarnWithdrawCalldata, type EarnWithdrawParams, type ForceDeallocation, type ForceRedeemParams, type ForceWithdrawParams, type MerklClaimCalldata, type MerklClaimResult, type MerklReward, type MerklRewardToken, type MerklRewardsResult, Network, OFT_ADAPTER_ABI, type OperationResult, type PrepareBridgeParams, STABLE_USDT_ADDRESS, STABLE_VAULT_ADDRESS, StableBulkError, type StableClient, type StableConfig, StableError, StableNetworkError, StableQuoteError, type StableReader, type StableReaderConfig, StableTransactionError, StableValidationError, type SwapParams, type SwapQuote, type TransferParams, type VaultPosition, type VaultYield, type VaultYieldReward, type WithdrawStatus, type YieldPreview, bridgeAssetFor, buildLzOptions, clearBridgeEstimateCache, createStable, createStableReader, erc3009Actions };
1016
+ export { BRIDGE_CHAIN_CONFIGS, type BridgeAsset, type BridgeCalldata, type BridgeCalldataStep, type BridgeChainConfig, type BridgeDeliveryState, type BridgeGasEstimate, type BridgeOftFee, type BridgeOftQuote, type BridgeParams, type BridgeQuote, type BridgeRoute, type BridgeStatus, type BridgeTimeEstimate, type BridgeTokenConfig, type BulkDepositOptions, type BulkEarnResult, type BulkEarnResultItem, type BulkWithdrawOptions, CHAIN_CONFIGS, Chain, type ChainConfig, type EarnConfig, type EarnDepositCalldata, type EarnDepositParams, type EarnRedeemParams, type EarnResult, type EarnWithdrawCalldata, type EarnWithdrawParams, type ForceDeallocation, type ForceRedeemParams, type ForceWithdrawParams, type MerklClaimCalldata, type MerklClaimResult, type MerklReward, type MerklRewardToken, type MerklRewardsResult, Network, OFT_ADAPTER_ABI, type OperationResult, type PrepareBridgeParams, STABLE_PYUSD_ADDRESS, STABLE_USDT_ADDRESS, STABLE_VAULT_ADDRESS, StableBulkError, type StableClient, type StableConfig, StableError, StableNetworkError, StableQuoteError, type StableReader, type StableReaderConfig, StableTransactionError, StableValidationError, type SwapParams, type SwapQuote, type TransferParams, type VaultPosition, type VaultYield, type VaultYieldReward, type WithdrawStatus, type YieldPreview, bridgeAssetFor, buildLzOptions, clearBridgeEstimateCache, createStable, createStableReader, erc3009Actions };
package/dist/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import {
2
2
  ERC3009_ABI,
3
+ STABLE_PYUSD_ADDRESS,
3
4
  STABLE_USDT_ADDRESS,
4
5
  STABLE_VAULT_ADDRESS,
5
6
  StableBulkError,
@@ -18,7 +19,7 @@ import {
18
19
  signTransferAuthorization,
19
20
  transferWithAuthorization,
20
21
  verifyAuthorization
21
- } from "./chunk-VS6GBRDF.js";
22
+ } from "./chunk-FN7OKBRH.js";
22
23
 
23
24
  // src/stable.ts
24
25
  import {
@@ -1750,8 +1751,14 @@ var XAUT0_DEPLOYMENTS = {
1750
1751
  ["plasma" /* Plasma */]: { address: "0x1B64B9025EEbb9A6239575dF9Ea4b9Ac46D4d193", decimals: 6, oftAdapter: "0x63aB93cBC9d4ecD9c4947b1A38F458147C08E6F7", approvalRequired: false },
1751
1752
  ["bsc" /* BSC */]: { address: "0x21cAef8A43163Eea865baeE23b9C2E327696A3bf", decimals: 6, oftAdapter: "0x53C3A64c8942288e12813C1F8457Db45980BcfC2", approvalRequired: false }
1752
1753
  };
1754
+ var PYUSD_DEPLOYMENTS = {
1755
+ // No floor: unlike USDT0's, this pathway's DVNs don't hold for finality. 15
1756
+ // confirmations compute to ~184s; LayerZero Scan observed ~202s (2026-10-27).
1757
+ ["ethereum" /* Ethereum */]: { address: "0x6c3ea9036406852006290770BEdFcAbA0e23A0e8", decimals: 6, oftAdapter: "0xa2C323fE5A74aDffAd2bf3E007E36bb029606444", approvalRequired: false, minDeliverySec: 0 },
1758
+ ["stable" /* Stable */]: { address: STABLE_PYUSD_ADDRESS, decimals: 6, oftAdapter: "0x2eb79387Fa1a6EF6DC8E25401C8fdc291Cc542C7", approvalRequired: false }
1759
+ };
1753
1760
  var USDT0_LOCKBOX_CHAINS = /* @__PURE__ */ new Set(["ethereum" /* Ethereum */, "sepolia" /* Sepolia */]);
1754
- function bridgeChain(chain, lzEid, blockTimeSec, usdt0Adapter) {
1761
+ function bridgeChain(chain, lzEid, blockTimeSec, usdt0Adapter, minDeliverySec) {
1755
1762
  const base = C[chain];
1756
1763
  const tokens = {};
1757
1764
  if (usdt0Adapter) {
@@ -1764,7 +1771,9 @@ function bridgeChain(chain, lzEid, blockTimeSec, usdt0Adapter) {
1764
1771
  }
1765
1772
  const xaut0 = XAUT0_DEPLOYMENTS[chain];
1766
1773
  if (xaut0) tokens.xaut0 = xaut0;
1767
- return { ...base, lzEid, blockTimeSec, tokens, oftAdapter: usdt0Adapter };
1774
+ const pyusd = PYUSD_DEPLOYMENTS[chain];
1775
+ if (pyusd) tokens.pyusd = pyusd;
1776
+ return { ...base, lzEid, blockTimeSec, minDeliverySec, tokens, oftAdapter: usdt0Adapter };
1768
1777
  }
1769
1778
  var BRIDGE_CHAIN_CONFIGS = {
1770
1779
  // ─── Testnet ───────────────────────────────────────────────────────────────
@@ -1772,18 +1781,18 @@ var BRIDGE_CHAIN_CONFIGS = {
1772
1781
  ["stable-testnet" /* StableTestnet */]: bridgeChain("stable-testnet" /* StableTestnet */, 40374, 0.7, "0x779Ded0c9e1022225f8E0630b35a9b54bE713736"),
1773
1782
  // ─── Mainnet ──────────────────────────────────────────────────────────────
1774
1783
  ["stable" /* Stable */]: bridgeChain("stable" /* Stable */, 30396, 0.7, "0xedaba024be4d87974d5aB11C6Dd586963CcCB027"),
1775
- ["ethereum" /* Ethereum */]: bridgeChain("ethereum" /* Ethereum */, 30101, 12, "0x6C96dE32CEa08842dcc4058c14d3aaAD7Fa41dee"),
1776
- ["arbitrum" /* Arbitrum */]: bridgeChain("arbitrum" /* Arbitrum */, 30110, 0.25, "0x14E4A1B13bf7F943c8ff7C51fb60FA964A298D92"),
1784
+ ["ethereum" /* Ethereum */]: bridgeChain("ethereum" /* Ethereum */, 30101, 12, "0x6C96dE32CEa08842dcc4058c14d3aaAD7Fa41dee", 1170),
1785
+ ["arbitrum" /* Arbitrum */]: bridgeChain("arbitrum" /* Arbitrum */, 30110, 0.25, "0x14E4A1B13bf7F943c8ff7C51fb60FA964A298D92", 1350),
1777
1786
  ["ink" /* Ink */]: bridgeChain("ink" /* Ink */, 30339, 1, "0x1cB6De532588fCA4a21B7209DE7C456AF8434A65"),
1778
- ["bera" /* Bera */]: bridgeChain("bera" /* Bera */, 30362, 2, "0x3Dc96399109df5ceb2C226664A086140bD0379cB"),
1787
+ ["bera" /* Bera */]: bridgeChain("bera" /* Bera */, 30362, 2, "0x3Dc96399109df5ceb2C226664A086140bD0379cB", 135),
1779
1788
  ["megaeth" /* MegaETH */]: bridgeChain("megaeth" /* MegaETH */, 30398, 1, "0x9151434b16b9763660705744891fa906f660ecc5"),
1780
1789
  ["hyperevm" /* HyperEVM */]: bridgeChain("hyperevm" /* HyperEVM */, 30367, 1, "0x904861a24F30EC96ea7CFC3bE9EA4B476d237e98"),
1781
- ["polygon" /* Polygon */]: bridgeChain("polygon" /* Polygon */, 30109, 1.5, "0x6BA10300f0DC58B7a1e4c0e41f5daBb7D7829e13"),
1790
+ ["polygon" /* Polygon */]: bridgeChain("polygon" /* Polygon */, 30109, 1.5, "0x6BA10300f0DC58B7a1e4c0e41f5daBb7D7829e13", 70),
1782
1791
  ["plasma" /* Plasma */]: bridgeChain("plasma" /* Plasma */, 30383, 1, "0x02ca37966753bDdDf11216B73B16C1dE756A7CF9"),
1783
1792
  ["optimism" /* Optimism */]: bridgeChain("optimism" /* Optimism */, 30111, 2, "0xF03b4d9AC1D5d1E7c4cEf54C2A313b9fe051A0aD"),
1784
1793
  ["unichain" /* Unichain */]: bridgeChain("unichain" /* Unichain */, 30320, 1, "0xc07bE8994D035631c36fb4a89C918CeFB2f03EC3"),
1785
1794
  ["sei" /* Sei */]: bridgeChain("sei" /* Sei */, 30280, 0.5, "0x56Fe74A2e3b484b921c447357203431a3485CC60"),
1786
- ["flare" /* Flare */]: bridgeChain("flare" /* Flare */, 30295, 1.1, "0x567287d2A9829215a37e3B88843d32f9221E7588"),
1795
+ ["flare" /* Flare */]: bridgeChain("flare" /* Flare */, 30295, 1.1, "0x567287d2A9829215a37e3B88843d32f9221E7588", 600),
1787
1796
  ["xlayer" /* XLayer */]: bridgeChain("xlayer" /* XLayer */, 30274, 1, "0x94BCCa6bdfd6A61817Ab0E960bFedE4984505554"),
1788
1797
  ["rootstock" /* Rootstock */]: bridgeChain("rootstock" /* Rootstock */, 30333, 31, "0x1a594d5d5d1c426281C1064B07f23F57B2716B61"),
1789
1798
  // XAUt0 only — BSC has no USDT0 deployment. Block time measured 2026-08-20.
@@ -1964,6 +1973,14 @@ function median(values) {
1964
1973
  const mid = Math.floor(sorted.length / 2);
1965
1974
  return sorted.length % 2 ? sorted[mid] : (sorted[mid - 1] + sorted[mid]) / 2;
1966
1975
  }
1976
+ function resolveDeliverySeconds(formulaSeconds, observedSeconds, minDeliverySec) {
1977
+ const base = formulaSeconds ?? observedSeconds;
1978
+ if (base === void 0) return void 0;
1979
+ if (minDeliverySec !== void 0 && minDeliverySec > base) {
1980
+ return { seconds: minDeliverySec, source: "floor" };
1981
+ }
1982
+ return { seconds: base, source: formulaSeconds !== void 0 ? "formula" : "observed" };
1983
+ }
1967
1984
  var WORKER_EXECUTOR = 1;
1968
1985
  var OPTION_LZRECEIVE = 1;
1969
1986
  var OPTION_NATIVE_DROP = 2;
@@ -2383,16 +2400,22 @@ var LayerZeroService = class {
2383
2400
  /**
2384
2401
  * Estimate how long a USDT0 bridge will take, end to end.
2385
2402
  *
2386
- * Two independent inputs, both cheap:
2387
- * - **observed** — median delivery time of recent messages LayerZero Scan has
2388
- * already settled on this exact pathway.
2389
- * - **formula** — LayerZero's documented estimate from the on-chain ULN config:
2390
- * `srcBlockTime × confirmations + dstBlockTime × (2 + dvnCount)`.
2403
+ * The number comes from the pathway's live ULN config:
2404
+ * `srcBlockTime × confirmations + dstBlockTime × (2 + dvnCount)`, floored at the
2405
+ * source chain's {@link BridgeChainConfig.minDeliverySec} where the confirmation
2406
+ * count is not the whole wait (unless the asset sets its own floor). This is what the DVNs are actually bound by, so it
2407
+ * tracks a config change the moment it lands — and on every pathway that is purely
2408
+ * confirmation-bound it agrees with both usdt0.to's own estimate and the delivery
2409
+ * times Scan reports to well under a percent.
2391
2410
  *
2392
- * `observed` wins when available. The formula assumes `confirmations` is the whole
2393
- * wait, which holds for L1 sources but badly understates rollups: Arbitrum→Stable
2394
- * computes to ~15s (60 blocks × 0.25s) while real deliveries take ~18min, because
2395
- * the DVNs wait for the L2 batch to finalize on L1.
2411
+ * The observed median of recent deliveries on this exact pathway is fetched too
2412
+ * and reported as {@link BridgeTimeEstimate.observedSeconds}, but it no longer
2413
+ * drives `seconds`. History lags the config: after Optimism→Stable was raised to
2414
+ * 1000 confirmations, a 50-message window still reaching back 261 days put the
2415
+ * median at ~15min against a real ~33min, and pathways quiet for months (Unichain,
2416
+ * XAUt0 from Arbitrum) were answering from configs that no longer exist. It stays
2417
+ * the fallback for the case the formula cannot be computed at all — an RPC that
2418
+ * will not serve the ULN read.
2396
2419
  */
2397
2420
  async estimateBridgeTime({
2398
2421
  fromChain,
@@ -2423,16 +2446,16 @@ var LayerZeroService = class {
2423
2446
  );
2424
2447
  formulaSeconds = Number.isFinite(computed) ? computed : void 0;
2425
2448
  }
2426
- const seconds = observedSeconds ?? formulaSeconds;
2427
- if (seconds === void 0) {
2449
+ const floor = srcToken.minDeliverySec ?? src.minDeliverySec;
2450
+ const resolved = resolveDeliverySeconds(formulaSeconds, observedSeconds, floor);
2451
+ if (!resolved) {
2428
2452
  throw new StableQuoteError({
2429
2453
  provider: "layerzero",
2430
2454
  shortMessage: `estimateBridgeTime: no pathway data for ${fromChain}\u2192${toChain}`
2431
2455
  });
2432
2456
  }
2433
2457
  return {
2434
- seconds,
2435
- source: observedSeconds !== void 0 ? "observed" : "formula",
2458
+ ...resolved,
2436
2459
  observedSeconds,
2437
2460
  formulaSeconds,
2438
2461
  confirmations: Number.isFinite(uln?.confirmations) ? uln?.confirmations : void 0,
@@ -2927,6 +2950,7 @@ export {
2927
2950
  ERC3009_ABI,
2928
2951
  Network,
2929
2952
  OFT_ADAPTER_ABI,
2953
+ STABLE_PYUSD_ADDRESS,
2930
2954
  STABLE_USDT_ADDRESS,
2931
2955
  STABLE_VAULT_ADDRESS,
2932
2956
  StableBulkError,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stablechain/sdk",
3
- "version": "1.0.7",
3
+ "version": "1.0.9",
4
4
  "description": "Stable SDK",
5
5
  "keywords": ["stable", "usdt", "gasless", "web3", "yield"],
6
6
  "license": "MIT",