@pushchain/core 6.0.19 → 6.0.21
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 +54 -0
- package/package.json +1 -1
- package/src/lib/cache/cache.js +2 -0
- package/src/lib/constants/abi/index.d.ts +1 -0
- package/src/lib/constants/abi/index.js +8 -1
- package/src/lib/constants/abi/pc20.evm.d.ts +217 -0
- package/src/lib/constants/abi/pc20.evm.js +150 -0
- package/src/lib/constants/abi/prc20.evm.d.ts +172 -0
- package/src/lib/constants/abi/prc20.evm.js +97 -0
- package/src/lib/constants/abi/universalGatewayV0.json +1 -1
- package/src/lib/constants/chain.js +38 -8
- package/src/lib/constants/selectors.js +2 -2
- package/src/lib/constants/tokens.js +4 -3
- package/src/lib/formatters.js +16 -6
- package/src/lib/generated/uexecutor/v1/query.js +2 -4
- package/src/lib/generated/uexecutor/v1/types.d.ts +14 -0
- package/src/lib/generated/uexecutor/v1/types.js +90 -47
- package/src/lib/generated/uexecutor/v2/query.js +2 -4
- package/src/lib/generated/uexecutor/v2/types.d.ts +20 -0
- package/src/lib/generated/uexecutor/v2/types.js +49 -33
- package/src/lib/generated/v1/tx.js +30 -37
- package/src/lib/index.d.ts +4 -1
- package/src/lib/index.js +21 -3
- package/src/lib/internal/buffer.js +1 -2
- package/src/lib/orchestrator/cea-utils.js +73 -83
- package/src/lib/orchestrator/internals/account-manager.js +130 -139
- package/src/lib/orchestrator/internals/cascade.d.ts +0 -6
- package/src/lib/orchestrator/internals/cascade.js +1184 -1059
- package/src/lib/orchestrator/internals/confirmation.js +138 -148
- package/src/lib/orchestrator/internals/error-decoder.js +1 -1
- package/src/lib/orchestrator/internals/errors.js +12 -3
- package/src/lib/orchestrator/internals/execute-funds-only.d.ts +2 -2
- package/src/lib/orchestrator/internals/execute-funds-only.js +297 -259
- package/src/lib/orchestrator/internals/execute-funds-payload.d.ts +2 -2
- package/src/lib/orchestrator/internals/execute-funds-payload.js +220 -220
- package/src/lib/orchestrator/internals/execute-standard.d.ts +0 -8
- package/src/lib/orchestrator/internals/execute-standard.js +339 -342
- package/src/lib/orchestrator/internals/gas-calculator.js +497 -520
- package/src/lib/orchestrator/internals/gas-usd-sizer.js +101 -110
- package/src/lib/orchestrator/internals/gateway-client.js +102 -103
- package/src/lib/orchestrator/internals/helpers.js +30 -27
- package/src/lib/orchestrator/internals/inbound-tracker.js +234 -238
- package/src/lib/orchestrator/internals/outbound-sync.js +463 -452
- package/src/lib/orchestrator/internals/outbound-tracker.js +27 -34
- package/src/lib/orchestrator/internals/payload-builder.d.ts +2 -2
- package/src/lib/orchestrator/internals/payload-builder.js +119 -100
- package/src/lib/orchestrator/internals/pc-usd-oracle.js +121 -129
- package/src/lib/orchestrator/internals/pc20/address-codec.d.ts +31 -0
- package/src/lib/orchestrator/internals/pc20/address-codec.js +124 -0
- package/src/lib/orchestrator/internals/pc20/chain-namespace.d.ts +68 -0
- package/src/lib/orchestrator/internals/pc20/chain-namespace.js +136 -0
- package/src/lib/orchestrator/internals/pc20/errors.d.ts +160 -0
- package/src/lib/orchestrator/internals/pc20/errors.js +236 -0
- package/src/lib/orchestrator/internals/pc20/export.d.ts +172 -0
- package/src/lib/orchestrator/internals/pc20/export.js +412 -0
- package/src/lib/orchestrator/internals/pc20/gate.d.ts +67 -0
- package/src/lib/orchestrator/internals/pc20/gate.js +184 -0
- package/src/lib/orchestrator/internals/pc20/resolver.d.ts +187 -0
- package/src/lib/orchestrator/internals/pc20/resolver.js +658 -0
- package/src/lib/orchestrator/internals/pc20/svm.d.ts +189 -0
- package/src/lib/orchestrator/internals/pc20/svm.js +286 -0
- package/src/lib/orchestrator/internals/pc20/tracking.d.ts +46 -0
- package/src/lib/orchestrator/internals/pc20/tracking.js +109 -0
- package/src/lib/orchestrator/internals/preflight.js +1 -1
- package/src/lib/orchestrator/internals/progress-route-hooks.js +2 -2
- package/src/lib/orchestrator/internals/push-chain-tx.js +319 -331
- package/src/lib/orchestrator/internals/quote.js +90 -94
- package/src/lib/orchestrator/internals/rescue.js +76 -79
- package/src/lib/orchestrator/internals/response-builder.d.ts +28 -1
- package/src/lib/orchestrator/internals/response-builder.js +817 -701
- package/src/lib/orchestrator/internals/route-handlers.d.ts +7 -15
- package/src/lib/orchestrator/internals/route-handlers.js +1512 -1178
- package/src/lib/orchestrator/internals/signing.js +78 -83
- package/src/lib/orchestrator/internals/svm-bridge.d.ts +2 -2
- package/src/lib/orchestrator/internals/svm-bridge.js +161 -93
- package/src/lib/orchestrator/internals/svm-helpers.d.ts +15 -1
- package/src/lib/orchestrator/internals/svm-helpers.js +68 -24
- package/src/lib/orchestrator/internals/svm-rent.d.ts +19 -1
- package/src/lib/orchestrator/internals/svm-rent.js +163 -141
- package/src/lib/orchestrator/internals/tx-transformer.js +26 -23
- package/src/lib/orchestrator/internals/uea-manager.js +89 -86
- package/src/lib/orchestrator/max-pc-for-gas.js +5 -6
- package/src/lib/orchestrator/orchestrator.js +217 -200
- package/src/lib/orchestrator/orchestrator.types.d.ts +121 -1
- package/src/lib/orchestrator/orchestrator.types.js +19 -0
- package/src/lib/orchestrator/payload-builders.d.ts +2 -2
- package/src/lib/orchestrator/payload-builders.js +26 -24
- package/src/lib/orchestrator/route-detector.js +26 -9
- package/src/lib/orchestrator/svm-idl/ix-encoder.js +1 -2
- package/src/lib/orchestrator/svm-idl/normalize-address.js +2 -2
- package/src/lib/orchestrator/svm-idl/resolve.js +1 -2
- package/src/lib/price-fetch/price-fetch.js +67 -68
- package/src/lib/progress-hook/progress-hook.js +124 -72
- package/src/lib/push-chain/push-chain.js +171 -153
- package/src/lib/push-client/push-client.js +223 -237
- package/src/lib/universal/account/account.js +349 -365
- package/src/lib/universal/signer/signer.d.ts +2 -1
- package/src/lib/universal/signer/signer.js +315 -299
- package/src/lib/universal-tx-detector/auto-detect.js +55 -60
- package/src/lib/universal-tx-detector/cascade.js +160 -172
- package/src/lib/universal-tx-detector/child-inbounds.js +67 -75
- package/src/lib/universal-tx-detector/classify.js +2 -3
- package/src/lib/universal-tx-detector/detector-svm.js +139 -147
- package/src/lib/universal-tx-detector/detector.js +145 -157
- package/src/lib/universal-tx-detector/normalize.js +7 -7
- package/src/lib/utils/external-tx-hash.js +1 -2
- package/src/lib/utils.d.ts +44 -0
- package/src/lib/utils.js +762 -683
- package/src/lib/vm-client/evm-client.js +186 -202
- package/src/lib/vm-client/svm-client.d.ts +1 -1
- package/src/lib/vm-client/svm-client.js +220 -224
- package/src/lib/vm-client/vm-client.types.d.ts +14 -2
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Typed PC20 errors.
|
|
4
|
+
*
|
|
5
|
+
* Every error carries a stable `code` discriminator so callers classify by
|
|
6
|
+
* `instanceof` or `err.code` rather than by parsing messages, and structured
|
|
7
|
+
* context fields (supplied chain, supplied address, expected chain, resolved
|
|
8
|
+
* namespace) plus a concise remediation hint.
|
|
9
|
+
*
|
|
10
|
+
* Two rules these must not break:
|
|
11
|
+
* - Never classify a token by symbol. PC20 identity is address-and-chain only.
|
|
12
|
+
* - Never embed raw RPC payloads in the message. Context fields are curated.
|
|
13
|
+
*/
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.PC20UnsafeEmptyPayloadError = exports.PC20ExportRevertedError = exports.PC20WrapperPredictionUnavailableError = exports.PC20UnknownChainNamespaceError = exports.PC20AmbiguousAddressError = exports.InsufficientPC20BalanceError = exports.UnsupportedPC20DestinationError = exports.PC20ExpectedButPRC20Error = exports.InvalidPC20MetadataError = exports.PC20FactoryMismatchError = exports.PC20RegistryMismatchError = exports.PC20WrapperNotRegisteredError = exports.PC20TokenChainMismatchError = exports.InvalidPC20AddressError = exports.PC20Error = void 0;
|
|
16
|
+
/** Base class for all PC20 failures. `instanceof PC20Error` catches the family. */
|
|
17
|
+
class PC20Error extends Error {
|
|
18
|
+
code;
|
|
19
|
+
chain;
|
|
20
|
+
address;
|
|
21
|
+
expectedChain;
|
|
22
|
+
chainNamespace;
|
|
23
|
+
hint;
|
|
24
|
+
constructor(code, message, ctx = {}) {
|
|
25
|
+
const parts = [message];
|
|
26
|
+
if (ctx.chain)
|
|
27
|
+
parts.push(`chain=${ctx.chain}`);
|
|
28
|
+
if (ctx.address)
|
|
29
|
+
parts.push(`address=${ctx.address}`);
|
|
30
|
+
if (ctx.expectedChain)
|
|
31
|
+
parts.push(`expectedChain=${ctx.expectedChain}`);
|
|
32
|
+
if (ctx.chainNamespace)
|
|
33
|
+
parts.push(`namespace=${ctx.chainNamespace}`);
|
|
34
|
+
if (ctx.hint)
|
|
35
|
+
parts.push(`— ${ctx.hint}`);
|
|
36
|
+
super(parts.join(' '));
|
|
37
|
+
this.name = new.target.name;
|
|
38
|
+
this.code = code;
|
|
39
|
+
this.chain = ctx.chain;
|
|
40
|
+
this.address = ctx.address;
|
|
41
|
+
this.expectedChain = ctx.expectedChain;
|
|
42
|
+
this.chainNamespace = ctx.chainNamespace;
|
|
43
|
+
this.hint = ctx.hint;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
exports.PC20Error = PC20Error;
|
|
47
|
+
/** Address is malformed for the supplied chain's VM, or is the zero/default address. */
|
|
48
|
+
class InvalidPC20AddressError extends PC20Error {
|
|
49
|
+
constructor(message, ctx = {}) {
|
|
50
|
+
super('PC20_INVALID_ADDRESS', message, ctx);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
exports.InvalidPC20AddressError = InvalidPC20AddressError;
|
|
54
|
+
/**
|
|
55
|
+
* `funds.token.chain` does not match where the funds actually are — the signer's
|
|
56
|
+
* chain for a direct external route, `params.from.chain` for a CEA-origin route,
|
|
57
|
+
* or the Push chain for an export.
|
|
58
|
+
*
|
|
59
|
+
* This is the check that stops a wrapper address copied onto the wrong chain.
|
|
60
|
+
*/
|
|
61
|
+
class PC20TokenChainMismatchError extends PC20Error {
|
|
62
|
+
constructor(ctx = {}) {
|
|
63
|
+
super('PC20_TOKEN_CHAIN_MISMATCH', 'PC20 token chain does not match the chain the funds are on.', {
|
|
64
|
+
hint: 'funds.token.chain must be where the token lives, not the ' +
|
|
65
|
+
'destination. `to.chain` is the destination.',
|
|
66
|
+
...ctx,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
exports.PC20TokenChainMismatchError = PC20TokenChainMismatchError;
|
|
71
|
+
/** UniversalCore has no source mapping for this wrapper on this chain. */
|
|
72
|
+
class PC20WrapperNotRegisteredError extends PC20Error {
|
|
73
|
+
constructor(ctx = {}) {
|
|
74
|
+
super('PC20_WRAPPER_NOT_REGISTERED', 'No PC20 wrapper is registered at this address on this chain.', {
|
|
75
|
+
hint: 'Confirm the wrapper has been deployed by an export to this chain, ' +
|
|
76
|
+
'and that the address belongs to this chain.',
|
|
77
|
+
...ctx,
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
exports.PC20WrapperNotRegisteredError = PC20WrapperNotRegisteredError;
|
|
82
|
+
/**
|
|
83
|
+
* Forward and reverse registry lookups disagree: `getPC20Source(wrapper)`
|
|
84
|
+
* resolved a source whose `getPC20Wrapper(source)` is a different address.
|
|
85
|
+
*
|
|
86
|
+
* A stale or partially-written registry entry. Never proceed — the burn would
|
|
87
|
+
* unlock the wrong Push token.
|
|
88
|
+
*/
|
|
89
|
+
class PC20RegistryMismatchError extends PC20Error {
|
|
90
|
+
constructor(ctx = {}) {
|
|
91
|
+
super('PC20_REGISTRY_MISMATCH', `PC20 registry forward/reverse mismatch${ctx.resolvedWrapper ? ` (reverse resolved to ${ctx.resolvedWrapper})` : ''}.`, { hint: 'This is a registry inconsistency; do not retry blindly.', ...ctx });
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
exports.PC20RegistryMismatchError = PC20RegistryMismatchError;
|
|
95
|
+
/**
|
|
96
|
+
* The live external gateway's configured `pc20Factory` differs from the
|
|
97
|
+
* reference factory (the destination Vault's, or UniversalCore's registry if
|
|
98
|
+
* exposed), or the factory does not recognize the wrapper.
|
|
99
|
+
*
|
|
100
|
+
* Proceeding risks the gateway taking the non-PC20 path for this token.
|
|
101
|
+
*/
|
|
102
|
+
class PC20FactoryMismatchError extends PC20Error {
|
|
103
|
+
constructor(ctx = {}) {
|
|
104
|
+
super('PC20_FACTORY_MISMATCH', 'PC20 factory identity mismatch between the live gateway and UniversalCore.', {
|
|
105
|
+
hint: 'The deployment is misconfigured; report it rather than retrying.',
|
|
106
|
+
...ctx,
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
exports.PC20FactoryMismatchError = PC20FactoryMismatchError;
|
|
111
|
+
/** Token does not implement `pc20Metadata()`, or the metadata fails validation. */
|
|
112
|
+
class InvalidPC20MetadataError extends PC20Error {
|
|
113
|
+
constructor(message, ctx = {}) {
|
|
114
|
+
super('PC20_INVALID_METADATA', message, ctx);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
exports.InvalidPC20MetadataError = InvalidPC20MetadataError;
|
|
118
|
+
/**
|
|
119
|
+
* A synthetic PRC20 address was supplied where a Push-native PC20 was expected.
|
|
120
|
+
*
|
|
121
|
+
* Distinct from {@link InvalidPC20MetadataError}: a PRC20 is a legitimate token
|
|
122
|
+
* on the wrong API, not a broken one. Kept separate so the message can point at
|
|
123
|
+
* the right call instead of reading as "your token is invalid".
|
|
124
|
+
*/
|
|
125
|
+
class PC20ExpectedButPRC20Error extends PC20Error {
|
|
126
|
+
constructor(ctx = {}) {
|
|
127
|
+
super('PC20_EXPECTED_BUT_PRC20', 'This address is a synthetic PRC20, not a Push-native PC20.', {
|
|
128
|
+
hint: 'Move PRC20 tokens with the MoveableToken API ' +
|
|
129
|
+
'(pushChainClient.moveable.token.*), not a { chain, address } PC20 reference.',
|
|
130
|
+
...ctx,
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
exports.PC20ExpectedButPRC20Error = PC20ExpectedButPRC20Error;
|
|
135
|
+
/** Destination chain has no configured PC20 factory, or is not supported for PC20. */
|
|
136
|
+
class UnsupportedPC20DestinationError extends PC20Error {
|
|
137
|
+
constructor(ctx = {}) {
|
|
138
|
+
super('PC20_UNSUPPORTED_DESTINATION', 'PC20 export is not configured for this destination chain.', { hint: 'No PC20 factory is registered for this chain namespace.', ...ctx });
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
exports.UnsupportedPC20DestinationError = UnsupportedPC20DestinationError;
|
|
142
|
+
/** Caller's balance of the wrapper (inbound) or Push source (export) is short. */
|
|
143
|
+
class InsufficientPC20BalanceError extends PC20Error {
|
|
144
|
+
constructor(ctx = {}) {
|
|
145
|
+
super('PC20_INSUFFICIENT_BALANCE', `Insufficient PC20 balance${ctx.required !== undefined && ctx.available !== undefined
|
|
146
|
+
? ` (required ${ctx.required}, available ${ctx.available})`
|
|
147
|
+
: ''}.`, ctx);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
exports.InsufficientPC20BalanceError = InsufficientPC20BalanceError;
|
|
151
|
+
/**
|
|
152
|
+
* The same address is registered on more than one chain, resolving to
|
|
153
|
+
* different Push sources, and no `chain` was supplied to disambiguate.
|
|
154
|
+
*
|
|
155
|
+
* Only reachable from the lookup utility's optional-chain path. Picking the
|
|
156
|
+
* first match would be the one way that convenience could actively mislead —
|
|
157
|
+
* the caller would get a confident answer about the wrong token.
|
|
158
|
+
*/
|
|
159
|
+
class PC20AmbiguousAddressError extends PC20Error {
|
|
160
|
+
candidates;
|
|
161
|
+
constructor(address, candidates) {
|
|
162
|
+
super('PC20_AMBIGUOUS_ADDRESS', `Address is registered on ${candidates.length} chains with different Push sources ` +
|
|
163
|
+
`(${candidates.map((c) => `${c.chain}→${c.pushAddress}`).join(', ')}).`, {
|
|
164
|
+
address,
|
|
165
|
+
hint: 'Pass `chain` in the options to disambiguate.',
|
|
166
|
+
});
|
|
167
|
+
this.candidates = candidates;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
exports.PC20AmbiguousAddressError = PC20AmbiguousAddressError;
|
|
171
|
+
/**
|
|
172
|
+
* A chain namespace could not be mapped in either direction.
|
|
173
|
+
*
|
|
174
|
+
* Thrown rather than returning a negative result: an unmapped namespace reads
|
|
175
|
+
* from the registry as "not deployed", hiding the actual bug.
|
|
176
|
+
*/
|
|
177
|
+
class PC20UnknownChainNamespaceError extends PC20Error {
|
|
178
|
+
constructor(namespace, ctx = {}) {
|
|
179
|
+
super('PC20_UNKNOWN_CHAIN_NAMESPACE', 'Unknown PC20 chain namespace.', {
|
|
180
|
+
chainNamespace: namespace,
|
|
181
|
+
...ctx,
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
exports.PC20UnknownChainNamespaceError = PC20UnknownChainNamespaceError;
|
|
186
|
+
/**
|
|
187
|
+
* The destination wrapper address for a first export could not be predicted.
|
|
188
|
+
*
|
|
189
|
+
* Thrown strictly BEFORE approval. A first export commits the source token into
|
|
190
|
+
* VaultPC20 before the destination transfer is built, so an unverifiable
|
|
191
|
+
* prediction must abort rather than fall back to a guess.
|
|
192
|
+
*/
|
|
193
|
+
class PC20WrapperPredictionUnavailableError extends PC20Error {
|
|
194
|
+
constructor(ctx = {}) {
|
|
195
|
+
super('PC20_WRAPPER_PREDICTION_UNAVAILABLE', 'Could not determine the destination PC20 wrapper address for a first export.', {
|
|
196
|
+
hint: 'Aborted before approval so no funds are locked. Retry once the ' +
|
|
197
|
+
'destination factory is reachable.',
|
|
198
|
+
...ctx,
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
exports.PC20WrapperPredictionUnavailableError = PC20WrapperPredictionUnavailableError;
|
|
203
|
+
/** A PC20 export reverted after the source token was locked. Carries recovery context. */
|
|
204
|
+
class PC20ExportRevertedError extends PC20Error {
|
|
205
|
+
outboundTxId;
|
|
206
|
+
lockedAmount;
|
|
207
|
+
revertRecipient;
|
|
208
|
+
constructor(ctx = {}) {
|
|
209
|
+
super('PC20_EXPORT_REVERTED', 'PC20 export reverted after the source token was locked.', {
|
|
210
|
+
hint: 'Funds return to the revert recipient on Push Chain.',
|
|
211
|
+
...ctx,
|
|
212
|
+
});
|
|
213
|
+
this.outboundTxId = ctx.outboundTxId;
|
|
214
|
+
this.lockedAmount = ctx.lockedAmount;
|
|
215
|
+
this.revertRecipient = ctx.revertRecipient;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
exports.PC20ExportRevertedError = PC20ExportRevertedError;
|
|
219
|
+
/**
|
|
220
|
+
* A wrapper burn was about to be submitted without any Push-side payload.
|
|
221
|
+
*
|
|
222
|
+
* Until every supported Push Chain version treats selector-only PC20 payloads
|
|
223
|
+
* as an empty payload, broadcasting this shape can burn the wrapper and leave
|
|
224
|
+
* the canonical token permanently locked. The SDK therefore fails closed.
|
|
225
|
+
*/
|
|
226
|
+
class PC20UnsafeEmptyPayloadError extends PC20Error {
|
|
227
|
+
constructor(ctx = {}) {
|
|
228
|
+
super('PC20_UNSAFE_EMPTY_PAYLOAD', 'Refusing to submit a PC20 burn without a Push-side forwarding payload.', {
|
|
229
|
+
hint: 'Prepare the transaction again with an SDK version that always ' +
|
|
230
|
+
'attaches the PC20 transfer payload.',
|
|
231
|
+
...ctx,
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
exports.PC20UnsafeEmptyPayloadError = PC20UnsafeEmptyPayloadError;
|
|
236
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Push-to-external PC20 export.
|
|
3
|
+
*
|
|
4
|
+
* Three things differ from the PRC20 outbound path, and all three are
|
|
5
|
+
* load-bearing:
|
|
6
|
+
*
|
|
7
|
+
* 1. The payload carries the `PC20` selector plus the destination wrapper's
|
|
8
|
+
* metadata. The SDK builds this — unlike inbound, where the external
|
|
9
|
+
* gateway prepends the selector.
|
|
10
|
+
* 2. The gas quote comes from `getPC20ExportGasAndFees`, not
|
|
11
|
+
* `getOutboundTxGasAndFees`. Only the former knows about the first-export
|
|
12
|
+
* deployment overhead.
|
|
13
|
+
* 3. The source token IS approved to UGPC. This is the mirror image of
|
|
14
|
+
* inbound: an export locks the Push-native token into VaultPC20, so the
|
|
15
|
+
* gateway must be able to pull it.
|
|
16
|
+
*/
|
|
17
|
+
import { type Hex } from 'viem';
|
|
18
|
+
import { CHAIN } from '../../../constants/enums';
|
|
19
|
+
import type { OrchestratorContext } from '../context';
|
|
20
|
+
import { type PC20ResolverOptions, type ResolvedPC20 } from './resolver';
|
|
21
|
+
/** `bytes4(ascii("PC20"))`. Must match the chain's PC20 route selector. */
|
|
22
|
+
export declare const PC20_SELECTOR: "0x50433230";
|
|
23
|
+
/**
|
|
24
|
+
* Factory limits on the metadata forwarded to the destination.
|
|
25
|
+
*
|
|
26
|
+
* Mirrors `PC20Factory.MAX_NAME_LENGTH` / `MAX_SYMBOL_LENGTH`. Pinned by test
|
|
27
|
+
* against the reference contract revision — exceeding them reverts on the
|
|
28
|
+
* destination chain, long after the source token has been locked, so the SDK
|
|
29
|
+
* fails fast on the Push side instead.
|
|
30
|
+
*/
|
|
31
|
+
export declare const MAX_PC20_NAME_BYTES = 64;
|
|
32
|
+
export declare const MAX_PC20_SYMBOL_BYTES = 32;
|
|
33
|
+
/**
|
|
34
|
+
* Build the outbound payload:
|
|
35
|
+
*
|
|
36
|
+
* PC20_SELECTOR
|
|
37
|
+
* || abi.encode(destChainNamespace, name, symbol, decimals)
|
|
38
|
+
* || rawDestinationUserData
|
|
39
|
+
*
|
|
40
|
+
* The user data is appended raw, not ABI-encoded into the tuple — the
|
|
41
|
+
* destination settlement path strips the fixed-width prefix and forwards the
|
|
42
|
+
* remainder verbatim.
|
|
43
|
+
*/
|
|
44
|
+
export declare function buildPC20ExportPayload(params: {
|
|
45
|
+
destinationChain: CHAIN;
|
|
46
|
+
name: string;
|
|
47
|
+
symbol: string;
|
|
48
|
+
decimals: number;
|
|
49
|
+
destinationUserData?: Hex;
|
|
50
|
+
}): Hex;
|
|
51
|
+
/**
|
|
52
|
+
* Reject metadata the destination factory would refuse.
|
|
53
|
+
*
|
|
54
|
+
* Byte length, not character count — a multi-byte symbol can pass a `.length`
|
|
55
|
+
* check and still revert on chain.
|
|
56
|
+
*/
|
|
57
|
+
export declare function assertMetadataFitsFactoryLimits(name: string, symbol: string): void;
|
|
58
|
+
export type PC20GasQuote = {
|
|
59
|
+
gasToken: `0x${string}`;
|
|
60
|
+
gasFee: bigint;
|
|
61
|
+
protocolFee: bigint;
|
|
62
|
+
gasPrice: bigint;
|
|
63
|
+
chainNamespace: string;
|
|
64
|
+
gasLimitUsed: bigint;
|
|
65
|
+
isFirstExport: boolean;
|
|
66
|
+
/**
|
|
67
|
+
* `gasLimitUsed` plus a deployment-overhead margin — see
|
|
68
|
+
* {@link quotePC20Export} for why the margin is unconditional.
|
|
69
|
+
*/
|
|
70
|
+
gasLimitCeiling: bigint;
|
|
71
|
+
};
|
|
72
|
+
/**
|
|
73
|
+
* Quote a PC20 export.
|
|
74
|
+
*
|
|
75
|
+
* ## Why the deployment margin is unconditional
|
|
76
|
+
*
|
|
77
|
+
* `isFirstExport` is read before the transaction is included, so it is a
|
|
78
|
+
* time-of-check/time-of-use value. Two things can happen in between:
|
|
79
|
+
*
|
|
80
|
+
* - quoted `true`, another export deploys the wrapper first → the quote
|
|
81
|
+
* over-funds. Harmless.
|
|
82
|
+
* - quoted `false`, the wrapper turns out to be absent at execution (registry
|
|
83
|
+
* rollback, factory reconfiguration, reorg) → the quote under-funds by
|
|
84
|
+
* `pc20DeploymentGasOverhead` and the transfer strands on the destination
|
|
85
|
+
* with the source token already locked.
|
|
86
|
+
*
|
|
87
|
+
* The second is unrecoverable without operator intervention, so the ceiling
|
|
88
|
+
* always covers a deployment. `maxPCForGas` is a ceiling rather than a charge —
|
|
89
|
+
* the unspent remainder is not consumed — so the only cost is a higher required
|
|
90
|
+
* balance. `gasLimitUsed` itself is passed through unchanged.
|
|
91
|
+
*/
|
|
92
|
+
export declare function quotePC20Export(ctx: OrchestratorContext, pushPC20: `0x${string}`, destinationChain: CHAIN, gasLimit: bigint, opts: PC20ResolverOptions): Promise<PC20GasQuote>;
|
|
93
|
+
/**
|
|
94
|
+
* PC20 quote adapted to the shape `queryOutboundGasFee` returns, so the shared
|
|
95
|
+
* R2 gas-sizing code downstream is untouched.
|
|
96
|
+
*
|
|
97
|
+
* `nativeValueForGas` and `sizing` are intentionally absent — the caller's
|
|
98
|
+
* native-PC swap sizing consumes `gasFee`/`protocolFee`/`gasPrice` the same way
|
|
99
|
+
* it does for PRC20. What differs is only where the numbers came from.
|
|
100
|
+
*/
|
|
101
|
+
export declare function queryPC20OutboundGasFee(ctx: OrchestratorContext, pushPC20: `0x${string}`, gasLimit: bigint, destinationChain: CHAIN): Promise<{
|
|
102
|
+
gasToken: `0x${string}`;
|
|
103
|
+
gasFee: bigint;
|
|
104
|
+
protocolFee: bigint;
|
|
105
|
+
gasPrice: bigint;
|
|
106
|
+
gasLimitUsed: bigint;
|
|
107
|
+
universalCoreAddress: `0x${string}`;
|
|
108
|
+
isFirstExport: boolean;
|
|
109
|
+
gasLimitCeiling: bigint;
|
|
110
|
+
/**
|
|
111
|
+
* Always zero. Present only for shape-compatibility with
|
|
112
|
+
* `queryOutboundGasFee` — both the EVM and SVM callers size the actual
|
|
113
|
+
* native value themselves (estimateNativeValueForSwap) from gasFee, and
|
|
114
|
+
* never consume this field from the quote.
|
|
115
|
+
*/
|
|
116
|
+
nativeValueForGas: bigint;
|
|
117
|
+
}>;
|
|
118
|
+
export type DestinationWrapper = {
|
|
119
|
+
/** Chain-native address of the wrapper on the destination chain. */
|
|
120
|
+
address: string;
|
|
121
|
+
/** False when this address is a prediction for a not-yet-deployed wrapper. */
|
|
122
|
+
deployed: boolean;
|
|
123
|
+
};
|
|
124
|
+
/**
|
|
125
|
+
* Resolve the wrapper address the destination transfer should target.
|
|
126
|
+
*
|
|
127
|
+
* For a repeat export this is the registered wrapper. For a first export the
|
|
128
|
+
* wrapper does not exist yet, but the destination settlement mints into the CEA
|
|
129
|
+
* and then executes user data — so the SDK still needs the address in order to
|
|
130
|
+
* build the transfer that delivers funds to the actual recipient.
|
|
131
|
+
*
|
|
132
|
+
* ## Funds-at-risk ordering
|
|
133
|
+
*
|
|
134
|
+
* This must run BEFORE the source-token approval. By the time the outbound is
|
|
135
|
+
* submitted the token is locked in VaultPC20; a wrapper address that turns out
|
|
136
|
+
* to be wrong then means a transfer to a dead address with no way back except
|
|
137
|
+
* the revert path. Every failure here therefore throws rather than falling back
|
|
138
|
+
* to a guess.
|
|
139
|
+
*
|
|
140
|
+
* The prediction is read from the live factory's own `computeWrapperAddress`,
|
|
141
|
+
* which derives from its own `type(PC20Wrapper).creationCode`. That is why the
|
|
142
|
+
* SDK does not mirror the CREATE2 derivation locally: a mirrored init-code hash
|
|
143
|
+
* can drift from the deployed bytecode, while asking the factory cannot.
|
|
144
|
+
*
|
|
145
|
+
* ## Which factory to ask
|
|
146
|
+
*
|
|
147
|
+
* Two contracts hold a `pc20Factory` pointer, and they are not the same slot:
|
|
148
|
+
*
|
|
149
|
+
* - `UniversalCore.pc20FactoryByChain(ns)` on Push — the protocol's registry
|
|
150
|
+
* mirror, and the value Tier B cross-checks against.
|
|
151
|
+
* - `Vault.pc20Factory()` on the destination chain — the contract that
|
|
152
|
+
* actually calls `deployWrapper` at settlement (`Vault.sol:327`).
|
|
153
|
+
*
|
|
154
|
+
* The Vault is therefore the authoritative answer to "where will the wrapper
|
|
155
|
+
* land"; the registry copy can go stale without settlement noticing. The
|
|
156
|
+
* deployed UniversalCore does not expose `pc20FactoryByChain` — by chain-team
|
|
157
|
+
* decision the token mappings plus the Vault's own pointer are the supported
|
|
158
|
+
* surface — so the Vault read is the standing path. The registry attempt is
|
|
159
|
+
* kept first purely for forward compatibility: if a future upgrade adds the
|
|
160
|
+
* accessor, the two become cross-checked with no SDK change.
|
|
161
|
+
*/
|
|
162
|
+
export declare function resolveDestinationWrapper(ctx: OrchestratorContext, pushPC20: `0x${string}`, destinationChain: CHAIN, opts: PC20ResolverOptions): Promise<DestinationWrapper>;
|
|
163
|
+
/**
|
|
164
|
+
* Everything that must hold before a PC20 export approves or broadcasts.
|
|
165
|
+
*
|
|
166
|
+
* Ordered so the cheapest, most likely failures come first and nothing that
|
|
167
|
+
* touches funds runs until all of them pass.
|
|
168
|
+
*/
|
|
169
|
+
export declare function validatePC20Export(ctx: OrchestratorContext, resolved: ResolvedPC20, destinationChain: CHAIN, opts: PC20ResolverOptions): Promise<{
|
|
170
|
+
wrapper: DestinationWrapper;
|
|
171
|
+
namespace: string;
|
|
172
|
+
}>;
|