@pushchain/core 6.0.20 → 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 +48 -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 +3 -0
- 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 -329
- 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.js +306 -294
- 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
|
@@ -13,7 +13,6 @@ exports.calculateNativeAmountForDeposit = calculateNativeAmountForDeposit;
|
|
|
13
13
|
exports.calculateGasAmountFromAmountOutMinETH = calculateGasAmountFromAmountOutMinETH;
|
|
14
14
|
exports.estimateDepositFromLockedNative = estimateDepositFromLockedNative;
|
|
15
15
|
exports.estimateNativeForDesiredDeposit = estimateNativeForDesiredDeposit;
|
|
16
|
-
const tslib_1 = require("tslib");
|
|
17
16
|
const web3_js_1 = require("@solana/web3.js");
|
|
18
17
|
const viem_1 = require("viem");
|
|
19
18
|
const abi_1 = require("../../constants/abi");
|
|
@@ -99,142 +98,137 @@ const ZERO_ADDR = '0x0000000000000000000000000000000000000000';
|
|
|
99
98
|
// ============================================================================
|
|
100
99
|
// ERC-20 Allowance
|
|
101
100
|
// ============================================================================
|
|
102
|
-
function ensureErc20Allowance(ctx, evmClient, tokenAddress, spender, requiredAmount) {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
const resetTxHash = yield evmClient.writeContract({
|
|
117
|
-
abi: abi_1.ERC20_EVM,
|
|
118
|
-
address: tokenAddress,
|
|
119
|
-
functionName: 'approve',
|
|
120
|
-
args: [spender, BigInt(0)],
|
|
121
|
-
signer: ctx.universalSigner,
|
|
122
|
-
});
|
|
123
|
-
yield evmClient.waitForConfirmations({
|
|
124
|
-
txHash: resetTxHash,
|
|
125
|
-
confirmations: 1,
|
|
126
|
-
timeoutMs: chain_1.CHAIN_INFO[chain].timeout,
|
|
127
|
-
});
|
|
128
|
-
}
|
|
129
|
-
const setTxHash = yield evmClient.writeContract({
|
|
101
|
+
async function ensureErc20Allowance(ctx, evmClient, tokenAddress, spender, requiredAmount) {
|
|
102
|
+
const chain = ctx.universalSigner.account.chain;
|
|
103
|
+
const owner = ctx.universalSigner.account.address;
|
|
104
|
+
const currentAllowance = await evmClient.readContract({
|
|
105
|
+
abi: abi_1.ERC20_EVM,
|
|
106
|
+
address: tokenAddress,
|
|
107
|
+
functionName: 'allowance',
|
|
108
|
+
args: [owner, spender],
|
|
109
|
+
});
|
|
110
|
+
if (currentAllowance >= requiredAmount)
|
|
111
|
+
return;
|
|
112
|
+
if (currentAllowance > BigInt(0)) {
|
|
113
|
+
(0, context_1.printLog)(ctx, `Resetting existing allowance from ${currentAllowance.toString()} to 0 for spender ${spender}`);
|
|
114
|
+
const resetTxHash = await evmClient.writeContract({
|
|
130
115
|
abi: abi_1.ERC20_EVM,
|
|
131
116
|
address: tokenAddress,
|
|
132
117
|
functionName: 'approve',
|
|
133
|
-
args: [spender,
|
|
118
|
+
args: [spender, BigInt(0)],
|
|
134
119
|
signer: ctx.universalSigner,
|
|
135
120
|
});
|
|
136
|
-
|
|
137
|
-
txHash:
|
|
121
|
+
await evmClient.waitForConfirmations({
|
|
122
|
+
txHash: resetTxHash,
|
|
138
123
|
confirmations: 1,
|
|
139
124
|
timeoutMs: chain_1.CHAIN_INFO[chain].timeout,
|
|
140
125
|
});
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
if (updated < requiredAmount) {
|
|
149
|
-
(0, context_1.printLog)(ctx, 'Warning: allowance not updated yet; proceeding');
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
catch (_a) {
|
|
153
|
-
// ignore
|
|
154
|
-
}
|
|
126
|
+
}
|
|
127
|
+
const setTxHash = await evmClient.writeContract({
|
|
128
|
+
abi: abi_1.ERC20_EVM,
|
|
129
|
+
address: tokenAddress,
|
|
130
|
+
functionName: 'approve',
|
|
131
|
+
args: [spender, requiredAmount],
|
|
132
|
+
signer: ctx.universalSigner,
|
|
155
133
|
});
|
|
134
|
+
await evmClient.waitForConfirmations({
|
|
135
|
+
txHash: setTxHash,
|
|
136
|
+
confirmations: 1,
|
|
137
|
+
timeoutMs: chain_1.CHAIN_INFO[chain].timeout,
|
|
138
|
+
});
|
|
139
|
+
try {
|
|
140
|
+
const updated = await evmClient.readContract({
|
|
141
|
+
abi: abi_1.ERC20_EVM,
|
|
142
|
+
address: tokenAddress,
|
|
143
|
+
functionName: 'allowance',
|
|
144
|
+
args: [owner, spender],
|
|
145
|
+
});
|
|
146
|
+
if (updated < requiredAmount) {
|
|
147
|
+
(0, context_1.printLog)(ctx, 'Warning: allowance not updated yet; proceeding');
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
catch {
|
|
151
|
+
// ignore
|
|
152
|
+
}
|
|
156
153
|
}
|
|
157
154
|
// ============================================================================
|
|
158
155
|
// Outbound Gas Fee Query
|
|
159
156
|
// ============================================================================
|
|
160
|
-
function queryOutboundGasFee(ctx, prc20Token, gasLimit, destinationChain) {
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
157
|
+
async function queryOutboundGasFee(ctx, prc20Token, gasLimit, destinationChain) {
|
|
158
|
+
const gatewayPcAddress = (0, helpers_1.getUniversalGatewayPCAddress)();
|
|
159
|
+
const pushChain = (0, helpers_1.getPushChainForNetwork)(ctx.pushNetwork);
|
|
160
|
+
const rpcUrl = chain_1.CHAIN_INFO[pushChain]?.defaultRPC?.[0] || 'unknown';
|
|
161
|
+
(0, context_1.printLog)(ctx, `queryOutboundGasFee — [step 1] inputs: gateway=${gatewayPcAddress}, prc20Token=${prc20Token}, gasLimit=${gasLimit}, rpcUrl=${rpcUrl}`);
|
|
162
|
+
let universalCoreAddress;
|
|
163
|
+
try {
|
|
164
|
+
universalCoreAddress = await ctx.pushClient.readContract({
|
|
165
|
+
address: gatewayPcAddress,
|
|
166
|
+
abi: abi_1.UNIVERSAL_GATEWAY_PC,
|
|
167
|
+
functionName: 'universalCore',
|
|
168
|
+
args: [],
|
|
169
|
+
});
|
|
170
|
+
(0, context_1.printLog)(ctx, `queryOutboundGasFee — [step 2] universalCore resolved to: ${universalCoreAddress}`);
|
|
171
|
+
}
|
|
172
|
+
catch (err) {
|
|
173
|
+
(0, context_1.printLog)(ctx, `queryOutboundGasFee — [step 2] FAILED to read universalCore: ${err instanceof Error ? err.message : String(err)}`);
|
|
174
|
+
throw err;
|
|
175
|
+
}
|
|
176
|
+
const callData = (0, viem_1.encodeFunctionData)({
|
|
177
|
+
abi: abi_1.UNIVERSAL_CORE_EVM,
|
|
178
|
+
functionName: 'getOutboundTxGasAndFees',
|
|
179
|
+
args: [prc20Token, gasLimit],
|
|
180
|
+
});
|
|
181
|
+
(0, context_1.printLog)(ctx, `queryOutboundGasFee — [step 3] calling getOutboundTxGasAndFees on ${universalCoreAddress}`);
|
|
182
|
+
(0, context_1.printLog)(ctx, `queryOutboundGasFee — [step 3] eth_call: {"method":"eth_call","params":[{"to":"${universalCoreAddress}","data":"${callData}"},"latest"]}`);
|
|
183
|
+
let gasToken;
|
|
184
|
+
let gasFee;
|
|
185
|
+
let protocolFee;
|
|
186
|
+
let gasPrice = BigInt(0);
|
|
187
|
+
let gasLimitUsed = gasLimit;
|
|
188
|
+
try {
|
|
189
|
+
const result = await ctx.pushClient.readContract({
|
|
190
|
+
address: universalCoreAddress,
|
|
182
191
|
abi: abi_1.UNIVERSAL_CORE_EVM,
|
|
183
192
|
functionName: 'getOutboundTxGasAndFees',
|
|
184
193
|
args: [prc20Token, gasLimit],
|
|
185
194
|
});
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
195
|
+
gasToken = result[0];
|
|
196
|
+
gasFee = result[1];
|
|
197
|
+
protocolFee = result[2];
|
|
198
|
+
gasPrice = result[3];
|
|
199
|
+
gasLimitUsed = result[5] ?? gasLimit;
|
|
200
|
+
(0, context_1.printLog)(ctx, `queryOutboundGasFee — [step 4] success: gasToken=${gasToken}, gasFee=${gasFee}, protocolFee=${protocolFee}, gasPrice=${gasPrice}, gasLimitUsed=${gasLimitUsed}`);
|
|
201
|
+
}
|
|
202
|
+
catch (err) {
|
|
203
|
+
(0, context_1.printLog)(ctx, `queryOutboundGasFee — [step 3] FAILED: ${err instanceof Error ? err.message : String(err)}`);
|
|
204
|
+
throw err;
|
|
205
|
+
}
|
|
206
|
+
let nativeValueForGas;
|
|
207
|
+
let sizing;
|
|
208
|
+
if (destinationChain !== undefined) {
|
|
193
209
|
try {
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
args: [prc20Token, gasLimit],
|
|
210
|
+
sizing = await (0, gas_usd_sizer_1.sizeOutboundGas)(ctx, {
|
|
211
|
+
gasFee,
|
|
212
|
+
originChain: ctx.universalSigner.account.chain,
|
|
213
|
+
destinationChain,
|
|
199
214
|
});
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
215
|
+
// All categories — A, B, and C — return the sizer's calibrated gas leg.
|
|
216
|
+
// R3 consumers additionally bump `nativeValueForGas` by `overflowNativePc`
|
|
217
|
+
// when category === 'C' (see route-handlers.executeCeaToPush).
|
|
218
|
+
nativeValueForGas = sizing.gasLegNativePc + protocolFee;
|
|
219
|
+
(0, context_1.printLog)(ctx, `queryOutboundGasFee — [step 5] sizer: category=${sizing.category}, gasUsd=${sizing.gasUsd}, ` +
|
|
220
|
+
`gasLegNativePc=${sizing.gasLegNativePc}, overflowNativePc=${sizing.overflowNativePc}, nativeValueForGas=${nativeValueForGas}`);
|
|
206
221
|
}
|
|
207
222
|
catch (err) {
|
|
208
|
-
(0, context_1.printLog)(ctx, `queryOutboundGasFee — [step
|
|
209
|
-
throw err;
|
|
210
|
-
}
|
|
211
|
-
let nativeValueForGas;
|
|
212
|
-
let sizing;
|
|
213
|
-
if (destinationChain !== undefined) {
|
|
214
|
-
try {
|
|
215
|
-
sizing = yield (0, gas_usd_sizer_1.sizeOutboundGas)(ctx, {
|
|
216
|
-
gasFee,
|
|
217
|
-
originChain: ctx.universalSigner.account.chain,
|
|
218
|
-
destinationChain,
|
|
219
|
-
});
|
|
220
|
-
// All categories — A, B, and C — return the sizer's calibrated gas leg.
|
|
221
|
-
// R3 consumers additionally bump `nativeValueForGas` by `overflowNativePc`
|
|
222
|
-
// when category === 'C' (see route-handlers.executeCeaToPush).
|
|
223
|
-
nativeValueForGas = sizing.gasLegNativePc + protocolFee;
|
|
224
|
-
(0, context_1.printLog)(ctx, `queryOutboundGasFee — [step 5] sizer: category=${sizing.category}, gasUsd=${sizing.gasUsd}, ` +
|
|
225
|
-
`gasLegNativePc=${sizing.gasLegNativePc}, overflowNativePc=${sizing.overflowNativePc}, nativeValueForGas=${nativeValueForGas}`);
|
|
226
|
-
}
|
|
227
|
-
catch (err) {
|
|
228
|
-
(0, context_1.printLog)(ctx, `queryOutboundGasFee — [step 5] sizer failed (${err instanceof Error ? err.message : String(err)}); falling back to 1M buffer`);
|
|
229
|
-
nativeValueForGas = protocolFee + gasFee * GAS_FEE_BUFFER_MULTIPLIER;
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
else {
|
|
223
|
+
(0, context_1.printLog)(ctx, `queryOutboundGasFee — [step 5] sizer failed (${err instanceof Error ? err.message : String(err)}); falling back to 1M buffer`);
|
|
233
224
|
nativeValueForGas = protocolFee + gasFee * GAS_FEE_BUFFER_MULTIPLIER;
|
|
234
|
-
(0, context_1.printLog)(ctx, `queryOutboundGasFee — [step 5] no destinationChain provided; legacy 1M buffer: nativeValueForGas=${nativeValueForGas}`);
|
|
235
225
|
}
|
|
236
|
-
|
|
237
|
-
|
|
226
|
+
}
|
|
227
|
+
else {
|
|
228
|
+
nativeValueForGas = protocolFee + gasFee * GAS_FEE_BUFFER_MULTIPLIER;
|
|
229
|
+
(0, context_1.printLog)(ctx, `queryOutboundGasFee — [step 5] no destinationChain provided; legacy 1M buffer: nativeValueForGas=${nativeValueForGas}`);
|
|
230
|
+
}
|
|
231
|
+
return { gasToken, gasFee, protocolFee, nativeValueForGas, gasPrice, gasLimitUsed, universalCoreAddress, sizing };
|
|
238
232
|
}
|
|
239
233
|
// ============================================================================
|
|
240
234
|
// Uniswap V3 Pool Price Estimation
|
|
@@ -245,124 +239,121 @@ function queryOutboundGasFee(ctx, prc20Token, gasLimit, destinationChain) {
|
|
|
245
239
|
* Returns the estimated amount with a 2x safety buffer (excess is refunded by the contract).
|
|
246
240
|
* Falls back to a percentage of accountBalance if any on-chain query fails.
|
|
247
241
|
*/
|
|
248
|
-
function estimateNativeValueForSwap(ctx, universalCoreAddress, gasToken, gasFee, accountBalance) {
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
abi: UNIVERSAL_CORE_SWAP_HELPERS_ABI,
|
|
271
|
-
functionName: 'WPC',
|
|
272
|
-
args: [],
|
|
273
|
-
}),
|
|
274
|
-
ctx.pushClient.readContract({
|
|
275
|
-
address: universalCoreAddress,
|
|
276
|
-
abi: UNIVERSAL_CORE_SWAP_HELPERS_ABI,
|
|
277
|
-
functionName: 'uniswapV3Factory',
|
|
278
|
-
args: [],
|
|
279
|
-
}),
|
|
280
|
-
ctx.pushClient.readContract({
|
|
281
|
-
address: universalCoreAddress,
|
|
282
|
-
abi: UNIVERSAL_CORE_SWAP_HELPERS_ABI,
|
|
283
|
-
functionName: 'defaultFeeTier',
|
|
284
|
-
args: [gasToken],
|
|
285
|
-
}),
|
|
286
|
-
]);
|
|
287
|
-
if (!feeTier) {
|
|
288
|
-
(0, context_1.printLog)(ctx, `estimateNativeValueForSwap — no fee tier for gasToken, using balance fallback`);
|
|
289
|
-
return balanceFallback(accountBalance, BALANCE_FALLBACK_DIVISOR, GAS_RESERVE);
|
|
290
|
-
}
|
|
291
|
-
const pushChain = (0, helpers_1.getPushChainForNetwork)(ctx.pushNetwork);
|
|
292
|
-
const quoterAddress = (_b = (_a = chain_1.CHAIN_INFO[pushChain]) === null || _a === void 0 ? void 0 : _a.dex) === null || _b === void 0 ? void 0 : _b.uniV3QuoterV2;
|
|
293
|
-
if (quoterAddress && !quoterAddress.startsWith('0xTBD')) {
|
|
294
|
-
try {
|
|
295
|
-
const quote = yield ctx.pushClient.readContract({
|
|
296
|
-
address: quoterAddress,
|
|
297
|
-
abi: UNISWAP_V3_QUOTER_EXACT_OUTPUT_ABI,
|
|
298
|
-
functionName: 'quoteExactOutputSingle',
|
|
299
|
-
args: [
|
|
300
|
-
{
|
|
301
|
-
tokenIn: wpcAddress,
|
|
302
|
-
tokenOut: gasToken,
|
|
303
|
-
amount: gasFee,
|
|
304
|
-
fee: feeTier,
|
|
305
|
-
sqrtPriceLimitX96: BigInt(0),
|
|
306
|
-
},
|
|
307
|
-
],
|
|
308
|
-
});
|
|
309
|
-
const exactWpcNeeded = quote[0];
|
|
310
|
-
const result = (exactWpcNeeded * SWAP_BUFFER_NUM) / SWAP_BUFFER_DEN;
|
|
311
|
-
(0, context_1.printLog)(ctx, `estimateNativeValueForSwap — exactOutput quoter=${quoterAddress}, ` +
|
|
312
|
-
`wpcNeeded=${exactWpcNeeded}, withBuffer(2.2x)=${result}`);
|
|
313
|
-
return capSwapEstimate(result, accountBalance, GAS_RESERVE, exactWpcNeeded);
|
|
314
|
-
}
|
|
315
|
-
catch (quoteErr) {
|
|
316
|
-
(0, context_1.printLog)(ctx, `estimateNativeValueForSwap — exactOutput quote failed: ${quoteErr instanceof Error ? quoteErr.message : String(quoteErr)}, falling back to slot0 price`);
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
// Get pool address from factory
|
|
320
|
-
const poolAddress = yield ctx.pushClient.readContract({
|
|
321
|
-
address: factoryAddress,
|
|
322
|
-
abi: UNISWAP_V3_FACTORY_ABI,
|
|
323
|
-
functionName: 'getPool',
|
|
324
|
-
args: [wpcAddress, gasToken, feeTier],
|
|
325
|
-
});
|
|
326
|
-
if (poolAddress === ZERO_ADDR) {
|
|
327
|
-
(0, context_1.printLog)(ctx, `estimateNativeValueForSwap — pool not found, using balance fallback`);
|
|
328
|
-
return balanceFallback(accountBalance, BALANCE_FALLBACK_DIVISOR, GAS_RESERVE);
|
|
329
|
-
}
|
|
330
|
-
// Read slot0 for current price
|
|
331
|
-
const slot0 = yield ctx.pushClient.readContract({
|
|
332
|
-
address: poolAddress,
|
|
333
|
-
abi: UNISWAP_V3_POOL_SLOT0_ABI,
|
|
334
|
-
functionName: 'slot0',
|
|
242
|
+
async function estimateNativeValueForSwap(ctx, universalCoreAddress, gasToken, gasFee, accountBalance) {
|
|
243
|
+
// 2.2x safety buffer applied to the pool quote; excess is refunded by
|
|
244
|
+
// swapAndBurnGas. Composed of a 2x pool-slippage cushion plus 10%
|
|
245
|
+
// headroom that used to live in the R2 route-handler callers (×110/100
|
|
246
|
+
// after this function returned). Folded into one place here so the cap
|
|
247
|
+
// branch below correctly bounds the FINAL inflated value — the previous
|
|
248
|
+
// arrangement (outer ×1.10 on top of an inner cap that returned
|
|
249
|
+
// `balance - GAS_RESERVE`) caused a deterministic preflight failure
|
|
250
|
+
// whenever the cap fired: required = 1.10 × (balance − 3 PC) + 3 PC ≈
|
|
251
|
+
// balance × 1.10 − 0.3 PC > balance for any non-trivial balance. See
|
|
252
|
+
// preflight.ts:215.
|
|
253
|
+
const SWAP_BUFFER_NUM = BigInt(22);
|
|
254
|
+
const SWAP_BUFFER_DEN = BigInt(10);
|
|
255
|
+
const BALANCE_FALLBACK_DIVISOR = BigInt(10); // 10% of balance as fallback
|
|
256
|
+
const GAS_RESERVE = BigInt(3e18); // 3 UPC reserve for tx overhead
|
|
257
|
+
try {
|
|
258
|
+
// Read WPC, factory, and defaultFeeTier in parallel
|
|
259
|
+
const [wpcAddress, factoryAddress, feeTier] = await Promise.all([
|
|
260
|
+
ctx.pushClient.readContract({
|
|
261
|
+
address: universalCoreAddress,
|
|
262
|
+
abi: UNIVERSAL_CORE_SWAP_HELPERS_ABI,
|
|
263
|
+
functionName: 'WPC',
|
|
335
264
|
args: [],
|
|
336
|
-
})
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
265
|
+
}),
|
|
266
|
+
ctx.pushClient.readContract({
|
|
267
|
+
address: universalCoreAddress,
|
|
268
|
+
abi: UNIVERSAL_CORE_SWAP_HELPERS_ABI,
|
|
269
|
+
functionName: 'uniswapV3Factory',
|
|
270
|
+
args: [],
|
|
271
|
+
}),
|
|
272
|
+
ctx.pushClient.readContract({
|
|
273
|
+
address: universalCoreAddress,
|
|
274
|
+
abi: UNIVERSAL_CORE_SWAP_HELPERS_ABI,
|
|
275
|
+
functionName: 'defaultFeeTier',
|
|
276
|
+
args: [gasToken],
|
|
277
|
+
}),
|
|
278
|
+
]);
|
|
279
|
+
if (!feeTier) {
|
|
280
|
+
(0, context_1.printLog)(ctx, `estimateNativeValueForSwap — no fee tier for gasToken, using balance fallback`);
|
|
281
|
+
return balanceFallback(accountBalance, BALANCE_FALLBACK_DIVISOR, GAS_RESERVE);
|
|
282
|
+
}
|
|
283
|
+
const pushChain = (0, helpers_1.getPushChainForNetwork)(ctx.pushNetwork);
|
|
284
|
+
const quoterAddress = chain_1.CHAIN_INFO[pushChain]?.dex?.uniV3QuoterV2;
|
|
285
|
+
if (quoterAddress && !quoterAddress.startsWith('0xTBD')) {
|
|
286
|
+
try {
|
|
287
|
+
const quote = await ctx.pushClient.readContract({
|
|
288
|
+
address: quoterAddress,
|
|
289
|
+
abi: UNISWAP_V3_QUOTER_EXACT_OUTPUT_ABI,
|
|
290
|
+
functionName: 'quoteExactOutputSingle',
|
|
291
|
+
args: [
|
|
292
|
+
{
|
|
293
|
+
tokenIn: wpcAddress,
|
|
294
|
+
tokenOut: gasToken,
|
|
295
|
+
amount: gasFee,
|
|
296
|
+
fee: feeTier,
|
|
297
|
+
sqrtPriceLimitX96: BigInt(0),
|
|
298
|
+
},
|
|
299
|
+
],
|
|
300
|
+
});
|
|
301
|
+
const exactWpcNeeded = quote[0];
|
|
302
|
+
const result = (exactWpcNeeded * SWAP_BUFFER_NUM) / SWAP_BUFFER_DEN;
|
|
303
|
+
(0, context_1.printLog)(ctx, `estimateNativeValueForSwap — exactOutput quoter=${quoterAddress}, ` +
|
|
304
|
+
`wpcNeeded=${exactWpcNeeded}, withBuffer(2.2x)=${result}`);
|
|
305
|
+
return capSwapEstimate(result, accountBalance, GAS_RESERVE, exactWpcNeeded);
|
|
351
306
|
}
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
wpcNeeded = (gasFee * Q192) / priceNum;
|
|
307
|
+
catch (quoteErr) {
|
|
308
|
+
(0, context_1.printLog)(ctx, `estimateNativeValueForSwap — exactOutput quote failed: ${quoteErr instanceof Error ? quoteErr.message : String(quoteErr)}, falling back to slot0 price`);
|
|
355
309
|
}
|
|
356
|
-
const result = (wpcNeeded * SWAP_BUFFER_NUM) / SWAP_BUFFER_DEN;
|
|
357
|
-
(0, context_1.printLog)(ctx, `estimateNativeValueForSwap — pool=${poolAddress}, sqrtPriceX96=${sqrtPriceX96}, ` +
|
|
358
|
-
`wpcNeeded=${wpcNeeded}, withBuffer(2.2x)=${result}`);
|
|
359
|
-
return capSwapEstimate(result, accountBalance, GAS_RESERVE, wpcNeeded);
|
|
360
310
|
}
|
|
361
|
-
|
|
362
|
-
|
|
311
|
+
// Get pool address from factory
|
|
312
|
+
const poolAddress = await ctx.pushClient.readContract({
|
|
313
|
+
address: factoryAddress,
|
|
314
|
+
abi: UNISWAP_V3_FACTORY_ABI,
|
|
315
|
+
functionName: 'getPool',
|
|
316
|
+
args: [wpcAddress, gasToken, feeTier],
|
|
317
|
+
});
|
|
318
|
+
if (poolAddress === ZERO_ADDR) {
|
|
319
|
+
(0, context_1.printLog)(ctx, `estimateNativeValueForSwap — pool not found, using balance fallback`);
|
|
363
320
|
return balanceFallback(accountBalance, BALANCE_FALLBACK_DIVISOR, GAS_RESERVE);
|
|
364
321
|
}
|
|
365
|
-
|
|
322
|
+
// Read slot0 for current price
|
|
323
|
+
const slot0 = await ctx.pushClient.readContract({
|
|
324
|
+
address: poolAddress,
|
|
325
|
+
abi: UNISWAP_V3_POOL_SLOT0_ABI,
|
|
326
|
+
functionName: 'slot0',
|
|
327
|
+
args: [],
|
|
328
|
+
});
|
|
329
|
+
const sqrtPriceX96 = slot0[0];
|
|
330
|
+
if (!sqrtPriceX96 || sqrtPriceX96 === BigInt(0)) {
|
|
331
|
+
(0, context_1.printLog)(ctx, `estimateNativeValueForSwap — pool not initialized, using balance fallback`);
|
|
332
|
+
return balanceFallback(accountBalance, BALANCE_FALLBACK_DIVISOR, GAS_RESERVE);
|
|
333
|
+
}
|
|
334
|
+
// price (token1/token0 in raw units) = (sqrtPriceX96)² / 2¹⁹²
|
|
335
|
+
const Q192 = BigInt(1) << BigInt(192);
|
|
336
|
+
const priceNum = sqrtPriceX96 * sqrtPriceX96; // sqrtPrice² in Q192
|
|
337
|
+
// Uniswap V3 sorts tokens: token0 < token1 by address
|
|
338
|
+
const isGasTokenToken0 = gasToken.toLowerCase() < wpcAddress.toLowerCase();
|
|
339
|
+
let wpcNeeded;
|
|
340
|
+
if (isGasTokenToken0) {
|
|
341
|
+
// price = WPC_per_gasToken → wpcNeeded = gasFee * price
|
|
342
|
+
wpcNeeded = (gasFee * priceNum) / Q192;
|
|
343
|
+
}
|
|
344
|
+
else {
|
|
345
|
+
// price = gasToken_per_WPC → wpcNeeded = gasFee / price
|
|
346
|
+
wpcNeeded = (gasFee * Q192) / priceNum;
|
|
347
|
+
}
|
|
348
|
+
const result = (wpcNeeded * SWAP_BUFFER_NUM) / SWAP_BUFFER_DEN;
|
|
349
|
+
(0, context_1.printLog)(ctx, `estimateNativeValueForSwap — pool=${poolAddress}, sqrtPriceX96=${sqrtPriceX96}, ` +
|
|
350
|
+
`wpcNeeded=${wpcNeeded}, withBuffer(2.2x)=${result}`);
|
|
351
|
+
return capSwapEstimate(result, accountBalance, GAS_RESERVE, wpcNeeded);
|
|
352
|
+
}
|
|
353
|
+
catch (err) {
|
|
354
|
+
(0, context_1.printLog)(ctx, `estimateNativeValueForSwap — failed: ${err instanceof Error ? err.message : String(err)}, using balance fallback`);
|
|
355
|
+
return balanceFallback(accountBalance, BALANCE_FALLBACK_DIVISOR, GAS_RESERVE);
|
|
356
|
+
}
|
|
366
357
|
}
|
|
367
358
|
/**
|
|
368
359
|
* Bound the buffered swap estimate by the UEA's affordable PC.
|
|
@@ -400,169 +391,161 @@ function balanceFallback(balance, divisor, reserve) {
|
|
|
400
391
|
// ============================================================================
|
|
401
392
|
// Rescue Gas Fee Query
|
|
402
393
|
// ============================================================================
|
|
403
|
-
function queryRescueGasFee(ctx, prc20Token, destinationChain) {
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
394
|
+
async function queryRescueGasFee(ctx, prc20Token, destinationChain) {
|
|
395
|
+
const gatewayPcAddress = (0, helpers_1.getUniversalGatewayPCAddress)();
|
|
396
|
+
(0, context_1.printLog)(ctx, `queryRescueGasFee — inputs: gateway=${gatewayPcAddress}, prc20Token=${prc20Token}`);
|
|
397
|
+
let universalCoreAddress;
|
|
398
|
+
try {
|
|
399
|
+
universalCoreAddress = await ctx.pushClient.readContract({
|
|
400
|
+
address: gatewayPcAddress,
|
|
401
|
+
abi: abi_1.UNIVERSAL_GATEWAY_PC,
|
|
402
|
+
functionName: 'universalCore',
|
|
403
|
+
args: [],
|
|
404
|
+
});
|
|
405
|
+
(0, context_1.printLog)(ctx, `queryRescueGasFee — universalCore resolved to: ${universalCoreAddress}`);
|
|
406
|
+
}
|
|
407
|
+
catch (err) {
|
|
408
|
+
(0, context_1.printLog)(ctx, `queryRescueGasFee — FAILED to read universalCore: ${err instanceof Error ? err.message : String(err)}`);
|
|
409
|
+
throw err;
|
|
410
|
+
}
|
|
411
|
+
let gasToken;
|
|
412
|
+
let gasFee;
|
|
413
|
+
let rescueGasLimit;
|
|
414
|
+
let gasPrice;
|
|
415
|
+
try {
|
|
416
|
+
const result = await ctx.pushClient.readContract({
|
|
417
|
+
address: universalCoreAddress,
|
|
418
|
+
abi: abi_1.UNIVERSAL_CORE_EVM,
|
|
419
|
+
functionName: 'getRescueFundsGasLimit',
|
|
420
|
+
args: [prc20Token],
|
|
421
|
+
});
|
|
422
|
+
gasToken = result[0];
|
|
423
|
+
gasFee = result[1];
|
|
424
|
+
rescueGasLimit = result[2];
|
|
425
|
+
gasPrice = result[3];
|
|
426
|
+
(0, context_1.printLog)(ctx, `queryRescueGasFee — success: gasToken=${gasToken}, gasFee=${gasFee}, rescueGasLimit=${rescueGasLimit}, gasPrice=${gasPrice}`);
|
|
427
|
+
}
|
|
428
|
+
catch (err) {
|
|
429
|
+
(0, context_1.printLog)(ctx, `queryRescueGasFee — FAILED: ${err instanceof Error ? err.message : String(err)}`);
|
|
430
|
+
throw err;
|
|
431
|
+
}
|
|
432
|
+
let nativeValueForGas;
|
|
433
|
+
let sizing;
|
|
434
|
+
if (destinationChain !== undefined) {
|
|
425
435
|
try {
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
args: [prc20Token],
|
|
436
|
+
sizing = await (0, gas_usd_sizer_1.sizeOutboundGas)(ctx, {
|
|
437
|
+
gasFee,
|
|
438
|
+
originChain: ctx.universalSigner.account.chain,
|
|
439
|
+
destinationChain,
|
|
431
440
|
});
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
rescueGasLimit = result[2];
|
|
435
|
-
gasPrice = result[3];
|
|
436
|
-
(0, context_1.printLog)(ctx, `queryRescueGasFee — success: gasToken=${gasToken}, gasFee=${gasFee}, rescueGasLimit=${rescueGasLimit}, gasPrice=${gasPrice}`);
|
|
441
|
+
nativeValueForGas = sizing.gasLegNativePc;
|
|
442
|
+
(0, context_1.printLog)(ctx, `queryRescueGasFee — sizer: category=${sizing.category}, gasUsd=${sizing.gasUsd}, nativeValueForGas=${nativeValueForGas}`);
|
|
437
443
|
}
|
|
438
444
|
catch (err) {
|
|
439
|
-
(0, context_1.printLog)(ctx, `queryRescueGasFee —
|
|
440
|
-
throw err;
|
|
441
|
-
}
|
|
442
|
-
let nativeValueForGas;
|
|
443
|
-
let sizing;
|
|
444
|
-
if (destinationChain !== undefined) {
|
|
445
|
-
try {
|
|
446
|
-
sizing = yield (0, gas_usd_sizer_1.sizeOutboundGas)(ctx, {
|
|
447
|
-
gasFee,
|
|
448
|
-
originChain: ctx.universalSigner.account.chain,
|
|
449
|
-
destinationChain,
|
|
450
|
-
});
|
|
451
|
-
nativeValueForGas = sizing.gasLegNativePc;
|
|
452
|
-
(0, context_1.printLog)(ctx, `queryRescueGasFee — sizer: category=${sizing.category}, gasUsd=${sizing.gasUsd}, nativeValueForGas=${nativeValueForGas}`);
|
|
453
|
-
}
|
|
454
|
-
catch (err) {
|
|
455
|
-
(0, context_1.printLog)(ctx, `queryRescueGasFee — sizer failed (${err instanceof Error ? err.message : String(err)}); falling back to 1M buffer`);
|
|
456
|
-
nativeValueForGas = gasFee * GAS_FEE_BUFFER_MULTIPLIER;
|
|
457
|
-
}
|
|
458
|
-
}
|
|
459
|
-
else {
|
|
445
|
+
(0, context_1.printLog)(ctx, `queryRescueGasFee — sizer failed (${err instanceof Error ? err.message : String(err)}); falling back to 1M buffer`);
|
|
460
446
|
nativeValueForGas = gasFee * GAS_FEE_BUFFER_MULTIPLIER;
|
|
461
|
-
(0, context_1.printLog)(ctx, `queryRescueGasFee — no destinationChain provided; legacy 1M buffer: nativeValueForGas=${nativeValueForGas}`);
|
|
462
447
|
}
|
|
463
|
-
|
|
464
|
-
|
|
448
|
+
}
|
|
449
|
+
else {
|
|
450
|
+
nativeValueForGas = gasFee * GAS_FEE_BUFFER_MULTIPLIER;
|
|
451
|
+
(0, context_1.printLog)(ctx, `queryRescueGasFee — no destinationChain provided; legacy 1M buffer: nativeValueForGas=${nativeValueForGas}`);
|
|
452
|
+
}
|
|
453
|
+
return { gasToken, gasFee, rescueGasLimit, gasPrice, nativeValueForGas, sizing };
|
|
465
454
|
}
|
|
466
455
|
// ============================================================================
|
|
467
456
|
// Native Amount Calculation for Deposit
|
|
468
457
|
// ============================================================================
|
|
469
|
-
function calculateNativeAmountForDeposit(ctx, chain, requiredFunds, ueaBalance,
|
|
458
|
+
async function calculateNativeAmountForDeposit(ctx, chain, requiredFunds, ueaBalance,
|
|
470
459
|
// When false, suppress the SEND-TX-103-03-04 ("Prepaid Deposit Estimated")
|
|
471
460
|
// progress hook so the caller can emit the full 103-03 sizing sequence
|
|
472
461
|
// (parent + Case A/B/C + terminal) AFTER 103-01/103-02, matching the
|
|
473
462
|
// funds-payload path ordering. The deposit math is unaffected.
|
|
474
463
|
opts) {
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
464
|
+
(0, context_1.fireProgressHook)(ctx, progress_hook_types_1.PROGRESS_HOOK.SEND_TX_102_01);
|
|
465
|
+
const oneUsd = utils_1.Utils.helpers.parseUnits('1', 8);
|
|
466
|
+
const maxUsd = utils_1.Utils.helpers.parseUnits('1000', 8);
|
|
467
|
+
const deficit = requiredFunds > ueaBalance ? requiredFunds - ueaBalance : BigInt(0);
|
|
468
|
+
let depositUsd = deficit > BigInt(0) ? ctx.pushClient.pushToUSDC(deficit) : oneUsd;
|
|
469
|
+
if (depositUsd < oneUsd)
|
|
470
|
+
depositUsd = oneUsd;
|
|
471
|
+
if (depositUsd > maxUsd)
|
|
472
|
+
throw new Error('Deposit value exceeds max $1000 worth of native token');
|
|
473
|
+
if (chain_1.CHAIN_INFO[chain].vm === enums_1.VM.SVM) {
|
|
474
|
+
const svmClient = new svm_client_1.SvmClient({
|
|
475
|
+
rpcUrls: ctx.rpcUrls[enums_1.CHAIN.SOLANA_DEVNET] ||
|
|
476
|
+
chain_1.CHAIN_INFO[enums_1.CHAIN.SOLANA_DEVNET].defaultRPC,
|
|
477
|
+
});
|
|
478
|
+
const programId = new web3_js_1.PublicKey(abi_1.SVM_GATEWAY_IDL.address);
|
|
479
|
+
const [configPda] = web3_js_1.PublicKey.findProgramAddressSync([(0, viem_1.stringToBytes)('config')], programId);
|
|
480
|
+
try {
|
|
481
|
+
const cfg = await svmClient.readContract({
|
|
482
|
+
abi: abi_1.SVM_GATEWAY_IDL,
|
|
483
|
+
address: abi_1.SVM_GATEWAY_IDL.address,
|
|
484
|
+
functionName: 'config',
|
|
485
|
+
args: [configPda.toBase58()],
|
|
490
486
|
});
|
|
491
|
-
const
|
|
492
|
-
const
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
const minCapUsd = BigInt(minField.toString());
|
|
503
|
-
const maxCapUsd = BigInt(maxField.toString());
|
|
504
|
-
if (depositUsd < minCapUsd)
|
|
505
|
-
depositUsd = minCapUsd;
|
|
506
|
-
const withMargin = (minCapUsd * BigInt(12)) / BigInt(10);
|
|
507
|
-
if (depositUsd < withMargin)
|
|
508
|
-
depositUsd = withMargin;
|
|
509
|
-
if (depositUsd > maxCapUsd)
|
|
510
|
-
depositUsd = maxCapUsd;
|
|
511
|
-
}
|
|
512
|
-
catch (_c) {
|
|
513
|
-
// best-effort
|
|
514
|
-
}
|
|
487
|
+
const minField = cfg.minCapUniversalTxUsd ?? cfg.min_cap_universal_tx_usd;
|
|
488
|
+
const maxField = cfg.maxCapUniversalTxUsd ?? cfg.max_cap_universal_tx_usd;
|
|
489
|
+
const minCapUsd = BigInt(minField.toString());
|
|
490
|
+
const maxCapUsd = BigInt(maxField.toString());
|
|
491
|
+
if (depositUsd < minCapUsd)
|
|
492
|
+
depositUsd = minCapUsd;
|
|
493
|
+
const withMargin = (minCapUsd * BigInt(12)) / BigInt(10);
|
|
494
|
+
if (depositUsd < withMargin)
|
|
495
|
+
depositUsd = withMargin;
|
|
496
|
+
if (depositUsd > maxCapUsd)
|
|
497
|
+
depositUsd = maxCapUsd;
|
|
515
498
|
}
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
const oneNativeUnit = utils_1.Utils.helpers.parseUnits('1', nativeDecimals);
|
|
519
|
-
let nativeAmount = (depositUsd * oneNativeUnit + (nativeTokenUsdPrice - BigInt(1))) /
|
|
520
|
-
nativeTokenUsdPrice;
|
|
521
|
-
nativeAmount = nativeAmount + BigInt(1);
|
|
522
|
-
if ((opts === null || opts === void 0 ? void 0 : opts.emitDepositEstimated) !== false) {
|
|
523
|
-
(0, context_1.fireProgressHook)(ctx, progress_hook_types_1.PROGRESS_HOOK.SEND_TX_103_03_04, nativeAmount, depositUsd, chain);
|
|
499
|
+
catch {
|
|
500
|
+
// best-effort
|
|
524
501
|
}
|
|
525
|
-
|
|
526
|
-
|
|
502
|
+
}
|
|
503
|
+
const nativeTokenUsdPrice = await new price_fetch_1.PriceFetch(ctx.rpcUrls).getPrice(chain);
|
|
504
|
+
const nativeDecimals = chain_1.CHAIN_INFO[chain].vm === enums_1.VM.SVM ? 9 : 18;
|
|
505
|
+
const oneNativeUnit = utils_1.Utils.helpers.parseUnits('1', nativeDecimals);
|
|
506
|
+
let nativeAmount = (depositUsd * oneNativeUnit + (nativeTokenUsdPrice - BigInt(1))) /
|
|
507
|
+
nativeTokenUsdPrice;
|
|
508
|
+
nativeAmount = nativeAmount + BigInt(1);
|
|
509
|
+
if (opts?.emitDepositEstimated !== false) {
|
|
510
|
+
(0, context_1.fireProgressHook)(ctx, progress_hook_types_1.PROGRESS_HOOK.SEND_TX_103_03_04, nativeAmount, depositUsd, chain);
|
|
511
|
+
}
|
|
512
|
+
return nativeAmount;
|
|
527
513
|
}
|
|
528
514
|
// ============================================================================
|
|
529
515
|
// ERC-20 Gas Amount from Exact Output Quote
|
|
530
516
|
// ============================================================================
|
|
531
|
-
function calculateGasAmountFromAmountOutMinETH(ctx, gasTokenAddress, amountOutMinETH, quoteExactOutputFn) {
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
if (!fromToken || !toToken) {
|
|
554
|
-
throw new Error('Token not supported for quoting');
|
|
555
|
-
}
|
|
556
|
-
const targetOut = BigInt(amountOutMinETH);
|
|
557
|
-
const exactOutQuote = yield quoteExactOutputFn(targetOut, {
|
|
558
|
-
from: fromToken,
|
|
559
|
-
to: toToken,
|
|
560
|
-
});
|
|
561
|
-
const requiredIn = BigInt(exactOutQuote.amountIn);
|
|
562
|
-
gasAmount = (requiredIn * BigInt(101)) / BigInt(100);
|
|
517
|
+
async function calculateGasAmountFromAmountOutMinETH(ctx, gasTokenAddress, amountOutMinETH, quoteExactOutputFn) {
|
|
518
|
+
const originChain = ctx.universalSigner.account.chain;
|
|
519
|
+
if (originChain !== enums_1.CHAIN.ETHEREUM_SEPOLIA &&
|
|
520
|
+
originChain !== enums_1.CHAIN.ARBITRUM_SEPOLIA &&
|
|
521
|
+
originChain !== enums_1.CHAIN.BASE_SEPOLIA) {
|
|
522
|
+
throw new Error('Gas payment in ERC-20 is supported only on Ethereum Sepolia, Arbitrum Sepolia, and Base Sepolia for now');
|
|
523
|
+
}
|
|
524
|
+
const WETH = chain_1.CHAIN_INFO[originChain].dex?.weth;
|
|
525
|
+
if (!WETH)
|
|
526
|
+
throw new Error('WETH address not configured for this chain');
|
|
527
|
+
let gasAmount;
|
|
528
|
+
if (gasTokenAddress.toLowerCase() === WETH.toLowerCase()) {
|
|
529
|
+
gasAmount = BigInt(amountOutMinETH);
|
|
530
|
+
}
|
|
531
|
+
else {
|
|
532
|
+
const fromList = tokens_1.PAYABLE_TOKENS[originChain] ?? [];
|
|
533
|
+
const fromToken = fromList.find((t) => (t.address || '').toLowerCase() === gasTokenAddress.toLowerCase());
|
|
534
|
+
const toList = (tokens_1.MOVEABLE_TOKENS[originChain] ?? []);
|
|
535
|
+
const toToken = toList.find((t) => t.symbol === 'WETH' ||
|
|
536
|
+
(t.address || '').toLowerCase() === (WETH || '').toLowerCase());
|
|
537
|
+
if (!fromToken || !toToken) {
|
|
538
|
+
throw new Error('Token not supported for quoting');
|
|
563
539
|
}
|
|
564
|
-
|
|
565
|
-
|
|
540
|
+
const targetOut = BigInt(amountOutMinETH);
|
|
541
|
+
const exactOutQuote = await quoteExactOutputFn(targetOut, {
|
|
542
|
+
from: fromToken,
|
|
543
|
+
to: toToken,
|
|
544
|
+
});
|
|
545
|
+
const requiredIn = BigInt(exactOutQuote.amountIn);
|
|
546
|
+
gasAmount = (requiredIn * BigInt(101)) / BigInt(100);
|
|
547
|
+
}
|
|
548
|
+
return { gasAmount };
|
|
566
549
|
}
|
|
567
550
|
// ============================================================================
|
|
568
551
|
// Estimate UPC deposit from locked ETH via Uniswap V3 quote
|
|
@@ -575,87 +558,84 @@ function calculateGasAmountFromAmountOutMinETH(ctx, gasTokenAddress, amountOutMi
|
|
|
575
558
|
* Queries the same Uniswap V3 QuoterV2 the chain uses in execute_inbound_gas.go.
|
|
576
559
|
* Returns 0 on any failure (caller should fall back to other logic).
|
|
577
560
|
*/
|
|
578
|
-
function estimateDepositFromLockedNative(ctx, nativeAmountForLocker, prc20Token) {
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
561
|
+
async function estimateDepositFromLockedNative(ctx, nativeAmountForLocker, prc20Token) {
|
|
562
|
+
try {
|
|
563
|
+
const pushChain = (0, helpers_1.getPushChainForNetwork)(ctx.pushNetwork);
|
|
564
|
+
const quoterAddress = chain_1.CHAIN_INFO[pushChain]?.dex?.uniV3QuoterV2;
|
|
565
|
+
if (!quoterAddress || quoterAddress.startsWith('0xTBD'))
|
|
566
|
+
return BigInt(0);
|
|
567
|
+
// Get UniversalCore → WPC address + fee tier (reuses existing ABI)
|
|
568
|
+
const gatewayPcAddress = (0, helpers_1.getUniversalGatewayPCAddress)();
|
|
569
|
+
const universalCoreAddress = await ctx.pushClient.readContract({
|
|
570
|
+
address: gatewayPcAddress,
|
|
571
|
+
abi: abi_1.UNIVERSAL_GATEWAY_PC,
|
|
572
|
+
functionName: 'universalCore',
|
|
573
|
+
args: [],
|
|
574
|
+
});
|
|
575
|
+
const [wpcAddress, feeTier] = await Promise.all([
|
|
576
|
+
ctx.pushClient.readContract({
|
|
577
|
+
address: universalCoreAddress,
|
|
578
|
+
abi: UNIVERSAL_CORE_SWAP_HELPERS_ABI,
|
|
579
|
+
functionName: 'WPC',
|
|
592
580
|
args: [],
|
|
593
|
-
})
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
return BigInt(0);
|
|
610
|
-
// QuoterV2.quoteExactInputSingle — same call the chain relay makes
|
|
611
|
-
const QUOTER_ABI = [
|
|
612
|
-
{
|
|
613
|
-
type: 'function',
|
|
614
|
-
name: 'quoteExactInputSingle',
|
|
615
|
-
inputs: [
|
|
616
|
-
{
|
|
617
|
-
type: 'tuple',
|
|
618
|
-
components: [
|
|
619
|
-
{ name: 'tokenIn', type: 'address' },
|
|
620
|
-
{ name: 'tokenOut', type: 'address' },
|
|
621
|
-
{ name: 'amountIn', type: 'uint256' },
|
|
622
|
-
{ name: 'fee', type: 'uint24' },
|
|
623
|
-
{ name: 'sqrtPriceLimitX96', type: 'uint160' },
|
|
624
|
-
],
|
|
625
|
-
},
|
|
626
|
-
],
|
|
627
|
-
outputs: [
|
|
628
|
-
{ name: 'amountOut', type: 'uint256' },
|
|
629
|
-
{ name: 'sqrtPriceX96After', type: 'uint160' },
|
|
630
|
-
{ name: 'initializedTicksCrossed', type: 'uint32' },
|
|
631
|
-
{ name: 'gasEstimate', type: 'uint256' },
|
|
632
|
-
],
|
|
633
|
-
stateMutability: 'view',
|
|
634
|
-
},
|
|
635
|
-
];
|
|
636
|
-
const result = yield ctx.pushClient.readContract({
|
|
637
|
-
address: quoterAddress,
|
|
638
|
-
abi: QUOTER_ABI,
|
|
639
|
-
functionName: 'quoteExactInputSingle',
|
|
640
|
-
args: [
|
|
581
|
+
}),
|
|
582
|
+
ctx.pushClient.readContract({
|
|
583
|
+
address: universalCoreAddress,
|
|
584
|
+
abi: UNIVERSAL_CORE_SWAP_HELPERS_ABI,
|
|
585
|
+
functionName: 'defaultFeeTier',
|
|
586
|
+
args: [prc20Token],
|
|
587
|
+
}),
|
|
588
|
+
]);
|
|
589
|
+
if (!feeTier || !wpcAddress)
|
|
590
|
+
return BigInt(0);
|
|
591
|
+
// QuoterV2.quoteExactInputSingle — same call the chain relay makes
|
|
592
|
+
const QUOTER_ABI = [
|
|
593
|
+
{
|
|
594
|
+
type: 'function',
|
|
595
|
+
name: 'quoteExactInputSingle',
|
|
596
|
+
inputs: [
|
|
641
597
|
{
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
598
|
+
type: 'tuple',
|
|
599
|
+
components: [
|
|
600
|
+
{ name: 'tokenIn', type: 'address' },
|
|
601
|
+
{ name: 'tokenOut', type: 'address' },
|
|
602
|
+
{ name: 'amountIn', type: 'uint256' },
|
|
603
|
+
{ name: 'fee', type: 'uint24' },
|
|
604
|
+
{ name: 'sqrtPriceLimitX96', type: 'uint160' },
|
|
605
|
+
],
|
|
647
606
|
},
|
|
648
607
|
],
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
608
|
+
outputs: [
|
|
609
|
+
{ name: 'amountOut', type: 'uint256' },
|
|
610
|
+
{ name: 'sqrtPriceX96After', type: 'uint160' },
|
|
611
|
+
{ name: 'initializedTicksCrossed', type: 'uint32' },
|
|
612
|
+
{ name: 'gasEstimate', type: 'uint256' },
|
|
613
|
+
],
|
|
614
|
+
stateMutability: 'view',
|
|
615
|
+
},
|
|
616
|
+
];
|
|
617
|
+
const result = await ctx.pushClient.readContract({
|
|
618
|
+
address: quoterAddress,
|
|
619
|
+
abi: QUOTER_ABI,
|
|
620
|
+
functionName: 'quoteExactInputSingle',
|
|
621
|
+
args: [
|
|
622
|
+
{
|
|
623
|
+
tokenIn: prc20Token,
|
|
624
|
+
tokenOut: wpcAddress,
|
|
625
|
+
amountIn: nativeAmountForLocker,
|
|
626
|
+
fee: feeTier,
|
|
627
|
+
sqrtPriceLimitX96: BigInt(0),
|
|
628
|
+
},
|
|
629
|
+
],
|
|
630
|
+
});
|
|
631
|
+
const amountOut = result[0];
|
|
632
|
+
(0, context_1.printLog)(ctx, `estimateDepositFromLockedNative — quote: ${nativeAmountForLocker.toString()} pETH → ${amountOut.toString()} WPC (fee tier: ${feeTier})`);
|
|
633
|
+
return amountOut;
|
|
634
|
+
}
|
|
635
|
+
catch (err) {
|
|
636
|
+
(0, context_1.printLog)(ctx, `estimateDepositFromLockedNative — failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
637
|
+
return BigInt(0);
|
|
638
|
+
}
|
|
659
639
|
}
|
|
660
640
|
/**
|
|
661
641
|
* Inverse of estimateDepositFromLockedNative: given a desired WPC output,
|
|
@@ -666,86 +646,83 @@ function estimateDepositFromLockedNative(ctx, nativeAmountForLocker, prc20Token)
|
|
|
666
646
|
* of the fixed $0.10/PC SDK rate. Returns 0 on any failure (caller should
|
|
667
647
|
* fall back to the fixed-rate sizing).
|
|
668
648
|
*/
|
|
669
|
-
function estimateNativeForDesiredDeposit(ctx, desiredWpc, prc20Token) {
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
649
|
+
async function estimateNativeForDesiredDeposit(ctx, desiredWpc, prc20Token) {
|
|
650
|
+
try {
|
|
651
|
+
if (desiredWpc <= BigInt(0))
|
|
652
|
+
return BigInt(0);
|
|
653
|
+
const pushChain = (0, helpers_1.getPushChainForNetwork)(ctx.pushNetwork);
|
|
654
|
+
const quoterAddress = chain_1.CHAIN_INFO[pushChain]?.dex?.uniV3QuoterV2;
|
|
655
|
+
if (!quoterAddress || quoterAddress.startsWith('0xTBD'))
|
|
656
|
+
return BigInt(0);
|
|
657
|
+
const gatewayPcAddress = (0, helpers_1.getUniversalGatewayPCAddress)();
|
|
658
|
+
const universalCoreAddress = await ctx.pushClient.readContract({
|
|
659
|
+
address: gatewayPcAddress,
|
|
660
|
+
abi: abi_1.UNIVERSAL_GATEWAY_PC,
|
|
661
|
+
functionName: 'universalCore',
|
|
662
|
+
args: [],
|
|
663
|
+
});
|
|
664
|
+
const [wpcAddress, feeTier] = await Promise.all([
|
|
665
|
+
ctx.pushClient.readContract({
|
|
666
|
+
address: universalCoreAddress,
|
|
667
|
+
abi: UNIVERSAL_CORE_SWAP_HELPERS_ABI,
|
|
668
|
+
functionName: 'WPC',
|
|
684
669
|
args: [],
|
|
685
|
-
})
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
if (!feeTier || !wpcAddress)
|
|
701
|
-
return BigInt(0);
|
|
702
|
-
const QUOTER_ABI = [
|
|
703
|
-
{
|
|
704
|
-
type: 'function',
|
|
705
|
-
name: 'quoteExactOutputSingle',
|
|
706
|
-
inputs: [
|
|
707
|
-
{
|
|
708
|
-
type: 'tuple',
|
|
709
|
-
components: [
|
|
710
|
-
{ name: 'tokenIn', type: 'address' },
|
|
711
|
-
{ name: 'tokenOut', type: 'address' },
|
|
712
|
-
{ name: 'amount', type: 'uint256' },
|
|
713
|
-
{ name: 'fee', type: 'uint24' },
|
|
714
|
-
{ name: 'sqrtPriceLimitX96', type: 'uint160' },
|
|
715
|
-
],
|
|
716
|
-
},
|
|
717
|
-
],
|
|
718
|
-
outputs: [
|
|
719
|
-
{ name: 'amountIn', type: 'uint256' },
|
|
720
|
-
{ name: 'sqrtPriceX96After', type: 'uint160' },
|
|
721
|
-
{ name: 'initializedTicksCrossed', type: 'uint32' },
|
|
722
|
-
{ name: 'gasEstimate', type: 'uint256' },
|
|
723
|
-
],
|
|
724
|
-
stateMutability: 'view',
|
|
725
|
-
},
|
|
726
|
-
];
|
|
727
|
-
const result = yield ctx.pushClient.readContract({
|
|
728
|
-
address: quoterAddress,
|
|
729
|
-
abi: QUOTER_ABI,
|
|
730
|
-
functionName: 'quoteExactOutputSingle',
|
|
731
|
-
args: [
|
|
670
|
+
}),
|
|
671
|
+
ctx.pushClient.readContract({
|
|
672
|
+
address: universalCoreAddress,
|
|
673
|
+
abi: UNIVERSAL_CORE_SWAP_HELPERS_ABI,
|
|
674
|
+
functionName: 'defaultFeeTier',
|
|
675
|
+
args: [prc20Token],
|
|
676
|
+
}),
|
|
677
|
+
]);
|
|
678
|
+
if (!feeTier || !wpcAddress)
|
|
679
|
+
return BigInt(0);
|
|
680
|
+
const QUOTER_ABI = [
|
|
681
|
+
{
|
|
682
|
+
type: 'function',
|
|
683
|
+
name: 'quoteExactOutputSingle',
|
|
684
|
+
inputs: [
|
|
732
685
|
{
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
686
|
+
type: 'tuple',
|
|
687
|
+
components: [
|
|
688
|
+
{ name: 'tokenIn', type: 'address' },
|
|
689
|
+
{ name: 'tokenOut', type: 'address' },
|
|
690
|
+
{ name: 'amount', type: 'uint256' },
|
|
691
|
+
{ name: 'fee', type: 'uint24' },
|
|
692
|
+
{ name: 'sqrtPriceLimitX96', type: 'uint160' },
|
|
693
|
+
],
|
|
738
694
|
},
|
|
739
695
|
],
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
696
|
+
outputs: [
|
|
697
|
+
{ name: 'amountIn', type: 'uint256' },
|
|
698
|
+
{ name: 'sqrtPriceX96After', type: 'uint160' },
|
|
699
|
+
{ name: 'initializedTicksCrossed', type: 'uint32' },
|
|
700
|
+
{ name: 'gasEstimate', type: 'uint256' },
|
|
701
|
+
],
|
|
702
|
+
stateMutability: 'view',
|
|
703
|
+
},
|
|
704
|
+
];
|
|
705
|
+
const result = await ctx.pushClient.readContract({
|
|
706
|
+
address: quoterAddress,
|
|
707
|
+
abi: QUOTER_ABI,
|
|
708
|
+
functionName: 'quoteExactOutputSingle',
|
|
709
|
+
args: [
|
|
710
|
+
{
|
|
711
|
+
tokenIn: prc20Token,
|
|
712
|
+
tokenOut: wpcAddress,
|
|
713
|
+
amount: desiredWpc,
|
|
714
|
+
fee: feeTier,
|
|
715
|
+
sqrtPriceLimitX96: BigInt(0),
|
|
716
|
+
},
|
|
717
|
+
],
|
|
718
|
+
});
|
|
719
|
+
const amountIn = result[0];
|
|
720
|
+
(0, context_1.printLog)(ctx, `estimateNativeForDesiredDeposit — quote: ${desiredWpc.toString()} WPC ← ${amountIn.toString()} pETH (fee tier: ${feeTier})`);
|
|
721
|
+
return amountIn;
|
|
722
|
+
}
|
|
723
|
+
catch (err) {
|
|
724
|
+
(0, context_1.printLog)(ctx, `estimateNativeForDesiredDeposit — failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
725
|
+
return BigInt(0);
|
|
726
|
+
}
|
|
750
727
|
}
|
|
751
728
|
//# sourceMappingURL=gas-calculator.js.map
|