@pushchain/core 6.0.22 → 6.0.24
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,3 +1,10 @@
|
|
|
1
|
+
@pushchain/core@6.0.23 (2026-09-01)
|
|
2
|
+
|
|
3
|
+
- docs: changelog entry for the EVM PC20 burn routing fix
|
|
4
|
+
- fix: route EVM PC20 imports through the payload path
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
1
8
|
@pushchain/core@6.0.22 (2026-08-14)
|
|
2
9
|
|
|
3
10
|
- fix: make PC20 first exports and Solana R3 E2E reliable
|
|
@@ -63,6 +70,16 @@
|
|
|
63
70
|
metadata, and added SVM remaining-account support required by the Solana
|
|
64
71
|
gateway.
|
|
65
72
|
|
|
73
|
+
- Fixed EVM PC20 wrapper burns destroying the wrapper without unlocking the
|
|
74
|
+
canonical token. A payload-less burn took the funds-only path, whose empty
|
|
75
|
+
payload gains the gateway's PC20 selector and then fails the chain's inbound
|
|
76
|
+
decode at ballot finalization — no handler runs, no revert is produced, and
|
|
77
|
+
the already-burned wrapper leaves the canonical token locked in VaultPC20.
|
|
78
|
+
The always-forward mitigation was gated to Solana; PC20 imports now route
|
|
79
|
+
through the payload path on both VMs, and `executeFundsOnly` fails closed
|
|
80
|
+
with `PC20UnsafeEmptyPayloadError` if a PC20 import ever reaches it again.
|
|
81
|
+
PRC20 and native funds-only flows are unchanged.
|
|
82
|
+
|
|
66
83
|
---
|
|
67
84
|
|
|
68
85
|
@pushchain/core@6.0.20 (2026-07-10)
|
package/package.json
CHANGED
|
@@ -31,11 +31,19 @@ const response_builder_1 = require("./response-builder");
|
|
|
31
31
|
const push_chain_tx_1 = require("./push-chain-tx");
|
|
32
32
|
const svm_helpers_1 = require("./svm-helpers");
|
|
33
33
|
const svm_1 = require("./pc20/svm");
|
|
34
|
+
const gate_1 = require("./pc20/gate");
|
|
34
35
|
const helpers_2 = require("./helpers");
|
|
35
36
|
const response_builder_2 = require("./response-builder");
|
|
36
37
|
const formatters_1 = require("../../formatters");
|
|
37
38
|
async function executeFundsOnly(ctx, execute, eventBuffer, getResponseCallbacks) {
|
|
38
39
|
const transformFn = (tx, buf = []) => (0, response_builder_2.transformToUniversalTxResponse)(ctx, tx, buf, getResponseCallbacks());
|
|
40
|
+
// Fail closed: a PC20 wrapper burn must never be broadcast from this path.
|
|
41
|
+
// It sends an empty payload, the gateway prepends the PC20 selector, and the
|
|
42
|
+
// chain's inbound decode hard-fails on the selector-only result with no
|
|
43
|
+
// revert — burning the wrapper and locking the canonical token forever.
|
|
44
|
+
// The orchestrator routes PC20 imports to the payload path; this is the
|
|
45
|
+
// backstop for any caller that reaches here anyway.
|
|
46
|
+
(0, gate_1.assertPC20ImportHasPayload)(execute, false, 'executeFundsOnly');
|
|
39
47
|
const chain = ctx.universalSigner.account.chain;
|
|
40
48
|
const { vm } = chain_1.CHAIN_INFO[chain];
|
|
41
49
|
if (!helpers_1.SUPPORTED_GATEWAY_CHAINS.includes(chain)) {
|
|
@@ -266,8 +266,8 @@ class Orchestrator {
|
|
|
266
266
|
// Single PC20 gate. Downstream builders only ever see the legacy
|
|
267
267
|
// PRC20/native shape; the PC20 branch is added here in Phase 2.
|
|
268
268
|
const legacy = await (0, gate_1.gateFunds)(this.ctx, execute);
|
|
269
|
-
//
|
|
270
|
-
// gateway prepends the PC20 selector to the (empty) payload and
|
|
269
|
+
// PC20 imports never take the raw funds-only path, on EITHER VM.
|
|
270
|
+
// The gateway prepends the PC20 selector to the (empty) payload and
|
|
271
271
|
// classifies the RESULT as FUNDS_AND_PAYLOAD, and the chain's
|
|
272
272
|
// inbound decode hard-fails on that selector-only payload with no
|
|
273
273
|
// revert — the wrapper is already burned (same "0x" vs "" guard as
|
|
@@ -275,9 +275,18 @@ class Orchestrator {
|
|
|
275
275
|
// payload (UEA multicall transfer to `to`), which classifies and
|
|
276
276
|
// decodes legitimately — the same always-forward mitigation R3
|
|
277
277
|
// ships on both VMs.
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
278
|
+
//
|
|
279
|
+
// This was previously gated on VM.SVM, which left EVM wrapper burns
|
|
280
|
+
// on the unsafe path: observed on Donut as a burned wrapper whose
|
|
281
|
+
// canonical token was never unlocked. The brick is at ballot
|
|
282
|
+
// finalization — NormalizeForTxType (x/uexecutor/types/inbound.go)
|
|
283
|
+
// strips the selector, gets '0x', which passes its `!= ""` empty
|
|
284
|
+
// check, and DecodeRawPayload('0x') then fails — so no handler runs
|
|
285
|
+
// at all: no deploy, no credit, and no INBOUND_REVERT. With a real
|
|
286
|
+
// forward payload the decode succeeds and the funds_and_payload
|
|
287
|
+
// handler deploys the UEA and credits normally.
|
|
288
|
+
const pc20Import = legacy._pc20?.direction === 'import';
|
|
289
|
+
return attachPerCallHookForWait(!hasData && !pc20Import
|
|
281
290
|
? await (0, internals_1.executeFundsOnly)(this.ctx, legacy, eventBuffer, rcb)
|
|
282
291
|
: await (0, internals_1.executeFundsWithPayload)(this.ctx, legacy, eventBuffer, rcb));
|
|
283
292
|
}
|