@pushchain/core 6.0.1 → 6.0.3

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/CHANGELOG.md CHANGED
@@ -1,4 +1,70 @@
1
- @pushchain/core@5.2.0 (unreleased)
1
+ @pushchain/core@6.0.2 (unreleased)
2
+
3
+ - Token constants now expose the missing `USDT.bsc` chain-suffix accessor,
4
+ while keeping `USDT.bnb` as a deprecated alias for backward compatibility.
5
+
6
+ - Updated Donut testnet stable token metadata to match the current source of
7
+ truth: external moveable token addresses are kept separate from Push Chain
8
+ PRC20 addresses, and the WPC/stable pool address audit table now reflects the
9
+ documented PRC20/pool pairs.
10
+
11
+ ---
12
+
13
+ @pushchain/core@6.0.1 (2026-05-15)
14
+
15
+ - Pre-flight UEA balance checks now default to warning-only behavior and
16
+ proceed when short. `sendTransaction` and `prepareTransaction` accept
17
+ `options.enforceGasCheck: true` to restore fail-fast behavior with
18
+ `InsufficientUEABalanceError`; pre-flight progress hooks now report
19
+ `WARNING` vs `ERROR` with shortfall metadata.
20
+
21
+ - Token constants added the `USDC.bsc` BSC suffix accessor while retaining
22
+ `USDC.bnb` as a deprecated compatibility alias.
23
+
24
+ - Consolidated tests, renamed transaction `target` fields to `recipient`, and
25
+ fixed SVM test cases around the release.
26
+
27
+ ---
28
+
29
+ @pushchain/core@6.0.0 (2026-05-14)
30
+
31
+ - Updated audit-driven contract and pool configuration, including BNB CEA
32
+ address changes and refreshed pool addresses.
33
+
34
+ - Fixed cascade, SVM payload, and SVM execution flows, with additional test-case
35
+ coverage for the audited scenarios.
36
+
37
+ - Improved PC amount formatting in transaction output and diagnostics.
38
+
39
+ ---
40
+
41
+ @pushchain/core@5.1.18 (2026-05-12)
42
+
43
+ - Added `executeTransactions` progress-hook coverage and fixed cascade
44
+ scenarios, including fresh-UEA and six-hop flows.
45
+
46
+ - Removed the `allowUnderfundedSwap` parameter and tightened native PC
47
+ formatting.
48
+
49
+ ---
50
+
51
+ @pushchain/core@5.1.17 (2026-05-07)
52
+
53
+ - Fixed the R3 EVM path tag so progress hooks emit the `303` route family
54
+ instead of `203`.
55
+
56
+ ---
57
+
58
+ @pushchain/core@5.1.16 (2026-05-07)
59
+
60
+ - Added pre-flight balance-check progress hooks.
61
+
62
+ - Fixed SVM rent checks, SVM upward ceiling behavior, cascade progress-hook
63
+ handling, and shared PC formatting.
64
+
65
+ ---
66
+
67
+ @pushchain/core@5.1.5 (2026-04-20)
2
68
 
3
69
  - Route 1 (UOA → Push) now applies Case A/B/C USD-bucket sizing to the
4
70
  Push-chain gas cost. Case A pads deposits to the $1 floor; Case B passes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pushchain/core",
3
- "version": "6.0.1",
3
+ "version": "6.0.3",
4
4
  "homepage": "https://push.org",
5
5
  "keywords": [
6
6
  "pushchain",
@@ -36,6 +36,8 @@ export declare const SYNTHETIC_PUSH_ERC20: Record<PUSH_NETWORK, {
36
36
  USDC_ARB: `0x${string}`;
37
37
  USDT_SOL: `0x${string}`;
38
38
  USDC_SOL: `0x${string}`;
39
+ USDT_BSC: `0x${string}`;
40
+ /** @deprecated Use USDT_BSC instead. */
39
41
  USDT_BNB: `0x${string}`;
40
42
  USDC_BSC: `0x${string}`;
41
43
  /** @deprecated Use USDC_BSC instead. */
@@ -62,6 +62,7 @@ exports.SYNTHETIC_PUSH_ERC20 = {
62
62
  USDC_ARB: '0x1091cCBA2FF8d2A131AE4B35e34cf3308C48572C',
63
63
  USDT_SOL: '0x4f1A3D22d170a2F4Bddb37845a962322e24f4e34',
64
64
  USDC_SOL: '0x04B8F634ABC7C879763F623e0f0550a4b5c4426F',
65
+ USDT_BSC: '0x731aF1Da5365259d27528557EE4aFBA4baC90ef2',
65
66
  USDT_BNB: '0x731aF1Da5365259d27528557EE4aFBA4baC90ef2',
66
67
  USDC_BSC: '0x120EBf25Dad7D6a09Ad2316f23f9Be95DBb90639',
67
68
  USDC_BNB: '0x120EBf25Dad7D6a09Ad2316f23f9Be95DBb90639',
@@ -83,6 +84,7 @@ exports.SYNTHETIC_PUSH_ERC20 = {
83
84
  USDC_ARB: '0x1091cCBA2FF8d2A131AE4B35e34cf3308C48572C',
84
85
  USDT_SOL: '0x4f1A3D22d170a2F4Bddb37845a962322e24f4e34',
85
86
  USDC_SOL: '0x04B8F634ABC7C879763F623e0f0550a4b5c4426F',
87
+ USDT_BSC: '0x731aF1Da5365259d27528557EE4aFBA4baC90ef2',
86
88
  USDT_BNB: '0x731aF1Da5365259d27528557EE4aFBA4baC90ef2',
87
89
  USDC_BSC: '0x120EBf25Dad7D6a09Ad2316f23f9Be95DBb90639',
88
90
  USDC_BNB: '0x120EBf25Dad7D6a09Ad2316f23f9Be95DBb90639',
@@ -104,6 +106,7 @@ exports.SYNTHETIC_PUSH_ERC20 = {
104
106
  USDC_ARB: '0xTBD',
105
107
  USDT_SOL: '0xTBD',
106
108
  USDC_SOL: '0xTBD',
109
+ USDT_BSC: '0xTBD',
107
110
  USDT_BNB: '0xTBD',
108
111
  USDC_BSC: '0xTBD',
109
112
  USDC_BNB: '0xTBD',
@@ -125,6 +128,7 @@ exports.SYNTHETIC_PUSH_ERC20 = {
125
128
  USDC_ARB: '0xTBD',
126
129
  USDT_SOL: '0xTBD',
127
130
  USDC_SOL: '0xTBD',
131
+ USDT_BSC: '0xTBD',
128
132
  USDT_BNB: '0xTBD',
129
133
  USDC_BSC: '0xTBD',
130
134
  USDC_BNB: '0xTBD',
@@ -73,6 +73,8 @@ export interface ChainSuffixAccessor {
73
73
  readonly eth: PushChainMoveableToken;
74
74
  readonly arb: PushChainMoveableToken;
75
75
  readonly base: PushChainMoveableToken;
76
+ readonly bsc: PushChainMoveableToken;
77
+ /** @deprecated Use `bsc` instead. */
76
78
  readonly bnb: PushChainMoveableToken;
77
79
  readonly sol: PushChainMoveableToken;
78
80
  }
@@ -85,7 +85,7 @@ const TOKEN_META = {
85
85
  USDT: {
86
86
  symbol: 'USDT',
87
87
  decimals: 6,
88
- address: '0x7169D38820dfd117C3FA1f22a697dBA58d90BA06',
88
+ address: '0xC4230aEaFcF6b8B49a7b4e53886420f00ff71876',
89
89
  mechanism: 'approve',
90
90
  },
91
91
  WETH: {
@@ -139,7 +139,7 @@ const TOKEN_META = {
139
139
  USDT: {
140
140
  symbol: 'USDT',
141
141
  decimals: 6,
142
- address: '0x1419d7C74D234fA6B73E06A2ce7822C1d37922f0',
142
+ address: '0xE30928528f52CAEeB75fB07837e22d77D47e9c07',
143
143
  mechanism: 'approve',
144
144
  },
145
145
  USDC: {
@@ -166,7 +166,7 @@ const TOKEN_META = {
166
166
  USDT: {
167
167
  symbol: 'USDT',
168
168
  decimals: 6,
169
- address: '0x9FF5a186f53F6E6964B00320Da1D2024DE11E0cB',
169
+ address: '0x4D7646B9eE3D68F4b0F135B5cbc66B00819F6b61',
170
170
  mechanism: 'approve',
171
171
  },
172
172
  USDC: {
@@ -193,13 +193,13 @@ const TOKEN_META = {
193
193
  USDT: {
194
194
  symbol: 'USDT',
195
195
  decimals: 6,
196
- address: '0xBC14F348BC9667be46b35Edc9B68653d86013DC5',
196
+ address: '0xE935d9c9C24D02E61186c640cc01d713C876d40F',
197
197
  mechanism: 'approve',
198
198
  },
199
199
  USDC: {
200
200
  symbol: 'USDC',
201
201
  decimals: 6,
202
- address: '0x64544969ed7EBf5f083679233325356EbE738930',
202
+ address: '0xA8802F96cAd0d45343d9bc660B6f7d80050A660b',
203
203
  mechanism: 'approve',
204
204
  },
205
205
  },
@@ -265,7 +265,7 @@ function buildPushChainMoveableTokenList() {
265
265
  mk('USDT', 6, s.USDT_ETH, enums_1.CHAIN.ETHEREUM_SEPOLIA),
266
266
  mk('USDT', 6, s.USDT_ARB, enums_1.CHAIN.ARBITRUM_SEPOLIA),
267
267
  mk('USDT', 6, s.USDT_BASE, enums_1.CHAIN.BASE_SEPOLIA),
268
- mk('USDT', 6, s.USDT_BNB, enums_1.CHAIN.BNB_TESTNET),
268
+ mk('USDT', 6, s.USDT_BSC, enums_1.CHAIN.BNB_TESTNET),
269
269
  mk('USDT', 6, s.USDT_SOL, enums_1.CHAIN.SOLANA_DEVNET),
270
270
  mk('USDC', 6, s.USDC_ETH, enums_1.CHAIN.ETHEREUM_SEPOLIA),
271
271
  mk('USDC', 6, s.USDC_ARB, enums_1.CHAIN.ARBITRUM_SEPOLIA),
@@ -365,6 +365,7 @@ function buildPushChainMoveableTokenAccessor() {
365
365
  sourceChain,
366
366
  prc20Address: address,
367
367
  });
368
+ const usdtBsc = mk('USDT', 6, s.USDT_BSC, enums_1.CHAIN.BNB_TESTNET);
368
369
  const usdcBsc = mk('USDC', 6, s.USDC_BSC, enums_1.CHAIN.BNB_TESTNET);
369
370
  return {
370
371
  pEth: mk('pETH', 18, s.pETH, enums_1.CHAIN.ETHEREUM_SEPOLIA),
@@ -379,7 +380,8 @@ function buildPushChainMoveableTokenAccessor() {
379
380
  eth: mk('USDT', 6, s.USDT_ETH, enums_1.CHAIN.ETHEREUM_SEPOLIA),
380
381
  arb: mk('USDT', 6, s.USDT_ARB, enums_1.CHAIN.ARBITRUM_SEPOLIA),
381
382
  base: mk('USDT', 6, s.USDT_BASE, enums_1.CHAIN.BASE_SEPOLIA),
382
- bnb: mk('USDT', 6, s.USDT_BNB, enums_1.CHAIN.BNB_TESTNET),
383
+ bsc: usdtBsc,
384
+ bnb: usdtBsc,
383
385
  sol: mk('USDT', 6, s.USDT_SOL, enums_1.CHAIN.SOLANA_DEVNET),
384
386
  },
385
387
  USDC: {
@@ -1,6 +1,6 @@
1
1
  import { CHAIN } from '../../constants/enums';
2
2
  import type { OrchestratorContext } from './context';
3
- type StableKey = 'USDT_ETH' | 'USDT_ARB' | 'USDT_BASE' | 'USDT_BNB' | 'USDC_BSC' | 'USDT_SOL';
3
+ type StableKey = 'USDT_ETH' | 'USDT_ARB' | 'USDT_BASE' | 'USDT_BSC' | 'USDC_BSC' | 'USDT_SOL';
4
4
  /**
5
5
  * Get $PC/USD price (8 decimals) for the given origin chain's route.
6
6
  * Returns 0 on any failure — caller is expected to fall back to
@@ -37,7 +37,7 @@ const ORIGIN_TO_STABLE = {
37
37
  [enums_1.CHAIN.ETHEREUM_SEPOLIA]: 'USDT_ETH',
38
38
  [enums_1.CHAIN.ARBITRUM_SEPOLIA]: 'USDT_ARB',
39
39
  [enums_1.CHAIN.BASE_SEPOLIA]: 'USDT_BASE',
40
- [enums_1.CHAIN.BNB_TESTNET]: 'USDT_BNB',
40
+ [enums_1.CHAIN.BNB_TESTNET]: 'USDT_BSC',
41
41
  [enums_1.CHAIN.SOLANA_DEVNET]: 'USDT_SOL',
42
42
  };
43
43
  /** Default decimals for stable PRC-20s on Push Chain. */
@@ -98,10 +98,10 @@ function reconstructProgressEvents(universalTxResponse, universalTxData) {
98
98
  // omitted from reconstruction because R1 doesn't register a UniversalTx
99
99
  // on Push Chain, so `universalTxData` is usually undefined here and we
100
100
  // have no reliable signal to tell the three paths apart. Callers who want
101
- // the full live sequence should either register `progressHook` at
102
- // `initialize()` time (client-level) or call `tx.progressHook(cb)` after
103
- // sendTransaction — both deliver the full stream from the execute-phase
104
- // event buffer.
101
+ // the full live sequence should register a progress hook at initialize
102
+ // time, pass `sendTransaction(params, { progressHook })`, or call
103
+ // `tx.progressHook(cb)` after sendTransaction — all deliver the full stream
104
+ // from the execute-phase event buffer.
105
105
  const events = [];
106
106
  const originParts = universalTxResponse.origin.split(':');
107
107
  const chainNamespace = originParts.length >= 2 ? `${originParts[0]}:${originParts[1]}` : originParts[0];
@@ -131,10 +131,33 @@ class Orchestrator {
131
131
  */
132
132
  execute(params, options) {
133
133
  return tslib_1.__awaiter(this, void 0, void 0, function* () {
134
- var _a, _b, _c, _d;
134
+ var _a, _b, _c, _d, _e;
135
135
  if (options) {
136
136
  params = Object.assign(Object.assign({}, params), { options: Object.assign(Object.assign({}, params.options), options) });
137
137
  }
138
+ const perCallHook = (_a = params.options) === null || _a === void 0 ? void 0 : _a.progressHook;
139
+ const originalExecuteHook = this.progressHook;
140
+ const currentHook = this.progressHook;
141
+ const shouldWrapPerCallHook = !!perCallHook &&
142
+ perCallHook !== currentHook &&
143
+ (currentHook === null || currentHook === void 0 ? void 0 : currentHook.__pushPerCallHook) !== perCallHook;
144
+ const attachPerCallHookForWait = (response) => {
145
+ if (perCallHook && response._setProgressHookNoReplay) {
146
+ response._setProgressHookNoReplay(perCallHook);
147
+ }
148
+ return response;
149
+ };
150
+ if (shouldWrapPerCallHook) {
151
+ const baseHook = this.progressHook;
152
+ const wrappedHook = ((event) => {
153
+ if (baseHook && baseHook !== perCallHook) {
154
+ baseHook(event);
155
+ }
156
+ perCallHook(event);
157
+ });
158
+ wrappedHook.__pushPerCallHook = perCallHook;
159
+ this.progressHook = wrappedHook;
160
+ }
138
161
  // Snapshot the caller's active route — `executeMultiChain` recurses into
139
162
  // this same method for R2/R3's inner Push-side execution, and without
140
163
  // snapshot/restore the recursive `detectRoute(params)` would clobber the
@@ -146,7 +169,7 @@ class Orchestrator {
146
169
  try {
147
170
  detectedRoute = (0, route_detector_1.detectRoute)(params);
148
171
  }
149
- catch (_e) {
172
+ catch (_f) {
150
173
  detectedRoute = route_detector_1.TransactionRoute.UOA_TO_PUSH;
151
174
  }
152
175
  // Don't downgrade an outer R2/R3/R4 route when the recursive inner call
@@ -164,14 +187,14 @@ class Orchestrator {
164
187
  // Lazy UEA upgrade check
165
188
  try {
166
189
  if (!this.accountStatusCache || !this.accountStatusCache.uea.loaded) {
167
- yield ((_a = this.accountStatusReadyPromise) !== null && _a !== void 0 ? _a : this.getAccountStatus());
190
+ yield ((_b = this.accountStatusReadyPromise) !== null && _b !== void 0 ? _b : this.getAccountStatus());
168
191
  }
169
192
  // If background resolved but cache still empty (timeout/error), fetch fresh
170
193
  if (!this.accountStatusCache || !this.accountStatusCache.uea.loaded) {
171
194
  yield this.getAccountStatus();
172
195
  }
173
- if (((_b = this.accountStatusCache) === null || _b === void 0 ? void 0 : _b.uea.deployed) &&
174
- ((_c = this.accountStatusCache) === null || _c === void 0 ? void 0 : _c.uea.requiresUpgrade)) {
196
+ if (((_c = this.accountStatusCache) === null || _c === void 0 ? void 0 : _c.uea.deployed) &&
197
+ ((_d = this.accountStatusCache) === null || _d === void 0 ? void 0 : _d.uea.requiresUpgrade)) {
175
198
  yield this.upgradeAccount({ progressHook: this.progressHook });
176
199
  }
177
200
  }
@@ -179,10 +202,10 @@ class Orchestrator {
179
202
  (0, internals_1.printLog)(this.ctx, `Lazy UEA upgrade check failed: ${err instanceof Error ? err.message : String(err)}. Proceeding with transaction.`);
180
203
  }
181
204
  // Check if this is a multi-chain request (has ChainTarget or from.chain)
182
- const isMultiChain = (0, route_detector_1.isChainTarget)(params.to) || ('from' in params && ((_d = params.from) === null || _d === void 0 ? void 0 : _d.chain));
205
+ const isMultiChain = (0, route_detector_1.isChainTarget)(params.to) || ('from' in params && ((_e = params.from) === null || _e === void 0 ? void 0 : _e.chain));
183
206
  if (isMultiChain) {
184
207
  try {
185
- return yield (0, internals_1.executeMultiChain)(this.ctx, params, this.execute.bind(this));
208
+ return attachPerCallHookForWait(yield (0, internals_1.executeMultiChain)(this.ctx, params, this.execute.bind(this)));
186
209
  }
187
210
  catch (err) {
188
211
  // R2/R3/R4 outer catch — fires the route-correct terminal failure
@@ -230,11 +253,11 @@ class Orchestrator {
230
253
  try {
231
254
  const rcb = () => this._getResponseCallbacks();
232
255
  if (execute.funds) {
233
- return !hasData
256
+ return attachPerCallHookForWait(!hasData
234
257
  ? yield (0, internals_1.executeFundsOnly)(this.ctx, execute, eventBuffer, rcb)
235
- : yield (0, internals_1.executeFundsWithPayload)(this.ctx, execute, eventBuffer, rcb);
258
+ : yield (0, internals_1.executeFundsWithPayload)(this.ctx, execute, eventBuffer, rcb));
236
259
  }
237
- return yield (0, internals_1.executeStandardPayload)(this.ctx, execute, eventBuffer, rcb);
260
+ return attachPerCallHookForWait(yield (0, internals_1.executeStandardPayload)(this.ctx, execute, eventBuffer, rcb));
238
261
  }
239
262
  catch (err) {
240
263
  const errMessage = err instanceof Error
@@ -277,6 +300,9 @@ class Orchestrator {
277
300
  }
278
301
  }
279
302
  finally {
303
+ if (shouldWrapPerCallHook) {
304
+ this.progressHook = originalExecuteHook;
305
+ }
280
306
  // Restore the caller's route so a recursive inner R1 execute doesn't
281
307
  // leak its UOA_TO_PUSH route back to the outer R2/R3 frame.
282
308
  this.currentRoute = previousRoute;
@@ -38,6 +38,15 @@ export interface TransactionExecutionOptions {
38
38
  * - true: emit the failure hook, throw InsufficientUEABalanceError, and stop
39
39
  */
40
40
  enforceGasCheck?: boolean;
41
+ /**
42
+ * Optional per-call progress callback for sendTransaction().
43
+ * Additive with the init-time `progressHook` passed to `PushChain.initialize`:
44
+ * both hooks receive every `ProgressEvent` emitted during this call. The
45
+ * callback is also registered on the returned response for wait-phase
46
+ * progress without replaying already-fired events. Dedups by reference if it
47
+ * matches the init-time hook.
48
+ */
49
+ progressHook?: (event: import('../progress-hook/progress-hook.types').ProgressEvent) => void;
41
50
  }
42
51
  export type ExecuteParams = {
43
52
  /**
@@ -184,10 +193,11 @@ export interface UniversalTxResponse {
184
193
  progressHook: (callback: (event: import('../progress-hook/progress-hook.types').ProgressEvent) => void) => void;
185
194
  /**
186
195
  * @internal Register a wait-phase progressHook without replaying buffered
187
- * events. Used by `trackTransaction()` to auto-attach the caller's per-call
188
- * progressHook so `tracked.wait()` can deliver wait-phase events (209-xx /
189
- * 299-xx / 399-xx) to the same callback — without re-emitting the
190
- * reconstructed execute-phase stream that trackTransaction already fired.
196
+ * events. Used by `sendTransaction(..., { progressHook })` and
197
+ * `trackTransaction()` to auto-attach the caller's per-call progressHook so
198
+ * `.wait()` can deliver wait-phase events (209-xx / 299-xx / 399-xx) to the
199
+ * same callback — without re-emitting the execute/reconstructed stream that
200
+ * already fired.
191
201
  */
192
202
  _setProgressHookNoReplay?: (callback: (event: import('../progress-hook/progress-hook.types').ProgressEvent) => void) => void;
193
203
  type: string;
@@ -71,6 +71,12 @@ export declare class PushChain {
71
71
  * @param options.enforceGasCheck - Defaults to false. When true, the
72
72
  * SDK stops on pre-flight gas/balance shortfall instead of warning
73
73
  * and proceeding.
74
+ * @param options.progressHook - Optional per-call progress callback.
75
+ * Additive with the init-time `progressHook` passed to `initialize`:
76
+ * both hooks receive every `ProgressEvent` emitted during this call.
77
+ * The callback is also registered on the returned response for wait()
78
+ * progress without replaying already-fired events. Dedups by reference
79
+ * if it matches the init-time hook.
74
80
  */
75
81
  sendTransaction: Orchestrator['execute'];
76
82
  /**
package/src/lib/utils.js CHANGED
@@ -696,7 +696,7 @@ Utils.tokens = {
696
696
  else if (isBaseFamily)
697
697
  key = 'USDT_BASE';
698
698
  else if (isBnbFamily)
699
- key = 'USDT_BNB';
699
+ key = 'USDT_BSC';
700
700
  else if (isSolFamily)
701
701
  key = 'USDT_SOL';
702
702
  else