four-flap-meme-sdk 1.7.9 → 1.7.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/eip7702/xlayer/bundle.js +4 -3
- package/dist/eip7702/xlayer/create-to-dex.js +4 -2
- package/dist/eip7702/xlayer/curve-to-dex.js +4 -2
- package/dist/eip7702/xlayer/disperse.js +4 -2
- package/dist/eip7702/xlayer/sign.js +4 -2
- package/dist/eip7702/xlayer/sweep.js +4 -2
- package/dist/index.d.ts +4 -1
- package/dist/index.js +2 -1
- package/dist/xlayer/eoa-bundle-swap.d.ts +46 -0
- package/dist/xlayer/eoa-bundle-swap.js +161 -0
- package/dist/xlayer/index.d.ts +4 -1
- package/dist/xlayer/index.js +2 -1
- package/package.json +1 -1
- package/dist/flap/portal-bundle-merkle/encryption.d.ts +0 -16
- package/dist/flap/portal-bundle-merkle/encryption.js +0 -146
|
@@ -34,11 +34,12 @@ function hashAuthorization(chainId, executorAddress, nonce) {
|
|
|
34
34
|
async function signAuthorization(wallet, nonce) {
|
|
35
35
|
const messageHash = hashAuthorization(XLAYER_CHAIN_ID, EXECUTOR_ADDRESS, nonce);
|
|
36
36
|
const signature = wallet.signingKey.sign(messageHash);
|
|
37
|
+
// 注意:EIP-7702 授权签名使用 yParity (0 或 1),不是 v (27 或 28)
|
|
37
38
|
return {
|
|
38
39
|
chainId: XLAYER_CHAIN_ID,
|
|
39
40
|
address: EXECUTOR_ADDRESS,
|
|
40
41
|
nonce,
|
|
41
|
-
v: signature.
|
|
42
|
+
v: signature.yParity,
|
|
42
43
|
r: signature.r,
|
|
43
44
|
s: signature.s,
|
|
44
45
|
};
|
|
@@ -207,10 +208,10 @@ export class XLayerBundle {
|
|
|
207
208
|
]);
|
|
208
209
|
const txHash = ethers.keccak256(unsigned);
|
|
209
210
|
const signature = sponsor.signingKey.sign(txHash);
|
|
210
|
-
//
|
|
211
|
+
// 添加签名(注意:Type 4 交易使用 yParity (0 或 1),不是 v (27 或 28))
|
|
211
212
|
const signedFields = [
|
|
212
213
|
...fields,
|
|
213
|
-
toRlpHex(signature.
|
|
214
|
+
toRlpHex(signature.yParity),
|
|
214
215
|
signature.r,
|
|
215
216
|
signature.s,
|
|
216
217
|
];
|
|
@@ -68,11 +68,12 @@ function hashAuthorization(chainId, executorAddress, nonce) {
|
|
|
68
68
|
function signAuthorization(wallet, nonce = 0) {
|
|
69
69
|
const messageHash = hashAuthorization(XLAYER_CHAIN_ID, EXECUTOR_ADDRESS, nonce);
|
|
70
70
|
const signature = wallet.signingKey.sign(messageHash);
|
|
71
|
+
// 注意:EIP-7702 授权签名使用 yParity (0 或 1),不是 v (27 或 28)
|
|
71
72
|
return {
|
|
72
73
|
chainId: XLAYER_CHAIN_ID,
|
|
73
74
|
address: EXECUTOR_ADDRESS,
|
|
74
75
|
nonce,
|
|
75
|
-
v: signature.
|
|
76
|
+
v: signature.yParity,
|
|
76
77
|
r: signature.r,
|
|
77
78
|
s: signature.s,
|
|
78
79
|
};
|
|
@@ -269,7 +270,8 @@ async function buildAndSignType4Transaction(rpcUrl, gasPrice, participants) {
|
|
|
269
270
|
const unsigned = ethers.concat([new Uint8Array([0x04]), ethers.encodeRlp(fields)]);
|
|
270
271
|
const txHashToSign = ethers.keccak256(unsigned);
|
|
271
272
|
const signature = sponsor.signingKey.sign(txHashToSign);
|
|
272
|
-
|
|
273
|
+
// 注意:Type 4 交易使用 yParity (0 或 1),不是 v (27 或 28)
|
|
274
|
+
const signedFields = [...fields, toRlpHex(signature.yParity), signature.r, signature.s];
|
|
273
275
|
const signedTx = ethers.hexlify(ethers.concat([new Uint8Array([0x04]), ethers.encodeRlp(signedFields)]));
|
|
274
276
|
const txHash = ethers.keccak256(signedTx);
|
|
275
277
|
return { signedTx, txHash, sponsorAddress: sponsor.address };
|
|
@@ -64,11 +64,12 @@ function hashAuthorization(chainId, executorAddress, nonce) {
|
|
|
64
64
|
function signAuthorization(wallet, nonce = 0) {
|
|
65
65
|
const messageHash = hashAuthorization(XLAYER_CHAIN_ID, EXECUTOR_ADDRESS, nonce);
|
|
66
66
|
const signature = wallet.signingKey.sign(messageHash);
|
|
67
|
+
// 注意:EIP-7702 授权签名使用 yParity (0 或 1),不是 v (27 或 28)
|
|
67
68
|
return {
|
|
68
69
|
chainId: XLAYER_CHAIN_ID,
|
|
69
70
|
address: EXECUTOR_ADDRESS,
|
|
70
71
|
nonce,
|
|
71
|
-
v: signature.
|
|
72
|
+
v: signature.yParity,
|
|
72
73
|
r: signature.r,
|
|
73
74
|
s: signature.s,
|
|
74
75
|
};
|
|
@@ -204,7 +205,8 @@ async function buildAndSignType4Transaction(rpcUrl, gasPrice, participants) {
|
|
|
204
205
|
const unsigned = ethers.concat([new Uint8Array([0x04]), ethers.encodeRlp(fields)]);
|
|
205
206
|
const txHashToSign = ethers.keccak256(unsigned);
|
|
206
207
|
const signature = sponsor.signingKey.sign(txHashToSign);
|
|
207
|
-
|
|
208
|
+
// 注意:Type 4 交易使用 yParity (0 或 1),不是 v (27 或 28)
|
|
209
|
+
const signedFields = [...fields, toRlpHex(signature.yParity), signature.r, signature.s];
|
|
208
210
|
const signedTx = ethers.hexlify(ethers.concat([new Uint8Array([0x04]), ethers.encodeRlp(signedFields)]));
|
|
209
211
|
const txHash = ethers.keccak256(signedTx);
|
|
210
212
|
return { signedTx, txHash, sponsorAddress: sponsor.address };
|
|
@@ -54,11 +54,12 @@ function hashAuthorization(chainId, executorAddress, nonce) {
|
|
|
54
54
|
function signAuthorization(wallet, nonce = 0) {
|
|
55
55
|
const messageHash = hashAuthorization(XLAYER_CHAIN_ID, EXECUTOR_ADDRESS, nonce);
|
|
56
56
|
const signature = wallet.signingKey.sign(messageHash);
|
|
57
|
+
// 注意:EIP-7702 授权签名使用 yParity (0 或 1),不是 v (27 或 28)
|
|
57
58
|
return {
|
|
58
59
|
chainId: XLAYER_CHAIN_ID,
|
|
59
60
|
address: EXECUTOR_ADDRESS,
|
|
60
61
|
nonce,
|
|
61
|
-
v: signature.
|
|
62
|
+
v: signature.yParity,
|
|
62
63
|
r: signature.r,
|
|
63
64
|
s: signature.s,
|
|
64
65
|
};
|
|
@@ -141,7 +142,8 @@ async function buildAndSignType4Transaction(config, participants) {
|
|
|
141
142
|
const unsigned = ethers.concat([new Uint8Array([0x04]), ethers.encodeRlp(fields)]);
|
|
142
143
|
const txHashToSign = ethers.keccak256(unsigned);
|
|
143
144
|
const signature = sponsor.signingKey.sign(txHashToSign);
|
|
144
|
-
|
|
145
|
+
// 注意:Type 4 交易使用 yParity (0 或 1),不是 v (27 或 28)
|
|
146
|
+
const signedFields = [...fields, toRlpHex(signature.yParity), signature.r, signature.s];
|
|
145
147
|
const signedTx = ethers.hexlify(ethers.concat([new Uint8Array([0x04]), ethers.encodeRlp(signedFields)]));
|
|
146
148
|
const txHash = ethers.keccak256(signedTx);
|
|
147
149
|
return { signedTx, txHash, sponsorAddress: sponsor.address };
|
|
@@ -124,11 +124,12 @@ function hashAuthorization(chainId, executorAddress, nonce) {
|
|
|
124
124
|
function signAuthorization(wallet, nonce = 0) {
|
|
125
125
|
const messageHash = hashAuthorization(XLAYER_CHAIN_ID, EXECUTOR_ADDRESS, nonce);
|
|
126
126
|
const signature = wallet.signingKey.sign(messageHash);
|
|
127
|
+
// 注意:EIP-7702 授权签名使用 yParity (0 或 1),不是 v (27 或 28)
|
|
127
128
|
return {
|
|
128
129
|
chainId: XLAYER_CHAIN_ID,
|
|
129
130
|
address: EXECUTOR_ADDRESS,
|
|
130
131
|
nonce,
|
|
131
|
-
v: signature.
|
|
132
|
+
v: signature.yParity,
|
|
132
133
|
r: signature.r,
|
|
133
134
|
s: signature.s,
|
|
134
135
|
};
|
|
@@ -220,9 +221,10 @@ async function buildAndSignType4Transaction(config, participants) {
|
|
|
220
221
|
]);
|
|
221
222
|
const txHashToSign = ethers.keccak256(unsigned);
|
|
222
223
|
const signature = sponsor.signingKey.sign(txHashToSign);
|
|
224
|
+
// 注意:Type 4 交易使用 yParity (0 或 1),不是 v (27 或 28)
|
|
223
225
|
const signedFields = [
|
|
224
226
|
...fields,
|
|
225
|
-
toRlpHex(signature.
|
|
227
|
+
toRlpHex(signature.yParity),
|
|
226
228
|
signature.r,
|
|
227
229
|
signature.s,
|
|
228
230
|
];
|
|
@@ -54,11 +54,12 @@ function hashAuthorization(chainId, executorAddress, nonce) {
|
|
|
54
54
|
function signAuthorization(wallet, nonce = 0) {
|
|
55
55
|
const messageHash = hashAuthorization(XLAYER_CHAIN_ID, EXECUTOR_ADDRESS, nonce);
|
|
56
56
|
const signature = wallet.signingKey.sign(messageHash);
|
|
57
|
+
// 注意:EIP-7702 授权签名使用 yParity (0 或 1),不是 v (27 或 28)
|
|
57
58
|
return {
|
|
58
59
|
chainId: XLAYER_CHAIN_ID,
|
|
59
60
|
address: EXECUTOR_ADDRESS,
|
|
60
61
|
nonce,
|
|
61
|
-
v: signature.
|
|
62
|
+
v: signature.yParity,
|
|
62
63
|
r: signature.r,
|
|
63
64
|
s: signature.s,
|
|
64
65
|
};
|
|
@@ -137,7 +138,8 @@ async function buildAndSignType4Transaction(config, participants) {
|
|
|
137
138
|
const unsigned = ethers.concat([new Uint8Array([0x04]), ethers.encodeRlp(fields)]);
|
|
138
139
|
const txHashToSign = ethers.keccak256(unsigned);
|
|
139
140
|
const signature = sponsor.signingKey.sign(txHashToSign);
|
|
140
|
-
|
|
141
|
+
// 注意:Type 4 交易使用 yParity (0 或 1),不是 v (27 或 28)
|
|
142
|
+
const signedFields = [...fields, toRlpHex(signature.yParity), signature.r, signature.s];
|
|
141
143
|
const signedTx = ethers.hexlify(ethers.concat([new Uint8Array([0x04]), ethers.encodeRlp(signedFields)]));
|
|
142
144
|
const txHash = ethers.keccak256(signedTx);
|
|
143
145
|
return { signedTx, txHash, sponsorAddress: sponsor.address };
|
package/dist/index.d.ts
CHANGED
|
@@ -54,6 +54,9 @@ submitDirectToRpcSequentialNoWait, // ✅ 顺序广播但不等待确认(用
|
|
|
54
54
|
submitDirectToRpcParallel, type DirectSubmitConfig, type DirectSubmitResult, type DirectTxResult } from './contracts/tm-bundle-merkle/submit.js';
|
|
55
55
|
export { directV2BatchBuy, directV2BatchSell, directV3BatchBuy, directV3BatchSell, getRouterAddress, DIRECT_ROUTERS, type DirectV2BuyParams, type DirectV2SellParams, type DirectV3BuyParams, type DirectV3SellParams, type DirectRouterResult, type DirectRouterSignConfig, type DexKey, type RouterVersion, } from './dex/index.js';
|
|
56
56
|
export * as XLayer from './xlayer/index.js';
|
|
57
|
-
export { bundleBuy as xlayerBundleBuy, bundleSell as xlayerBundleSell, bundleBuySell as xlayerBundleBuySell, bundleCreateBuySign as xlayerBundleCreateBuySign, bundleCreateToDexSign as xlayerBundleCreateToDexSign, bundleGraduateBuy as xlayerBundleGraduateBuy, bundleSwapSign as xlayerBundleSwapSign, bundleBatchSwapSign as xlayerBundleBatchSwapSign, createBundleExecutor as xlayerCreateBundleExecutor, BundleExecutor as XLayerBundleExecutor, makeVolume as xlayerMakeVolume, singleRoundVolume as xlayerSingleRoundVolume, createVolumeExecutor as xlayerCreateVolumeExecutor, VolumeExecutor as XLayerVolumeExecutor, makeBuyFirstVolume as xlayerMakeBuyFirstVolume, BuyFirstVolumeExecutor as XLayerBuyFirstVolumeExecutor, AAPortalBuyFirstExecutor as XLayerAAPortalBuyFirstExecutor, AADexBuyFirstExecutor as XLayerAADexBuyFirstExecutor, AAVolumeBuyFirstExecutor as XLayerAAVolumeBuyFirstExecutor, createAAVolumeBuyFirstExecutor as xlayerCreateAAVolumeBuyFirstExecutor, type VolumeBuyFirstParams as XLayerVolumeBuyFirstParams, type VolumeBuyFirstResult as XLayerVolumeBuyFirstResult, type VolumeContinuousParams as XLayerVolumeContinuousParams, type VolumeContinuousResult as XLayerVolumeContinuousResult, type VolumeProgress as XLayerVolumeProgress, createDexExecutor as xlayerCreateDexExecutor, createDexQuery as xlayerCreateDexQuery, quoteOkbToToken as xlayerQuoteOkbToToken, quoteTokenToOkb as xlayerQuoteTokenToOkb, DexExecutor as XLayerDexExecutor, DexQuery as XLayerDexQuery, buildWashOps, type WashOpsParams, type WashOpsResult, type WashPoolType, type WashUserType, buildBundleBuyOps, buildBundleSellOps, buildBundleProfitOp, filterOutProfitOps, type BundleBuyOpsParams, type BundleSellOpsParams, type BundleProfitOpParams, type BundleOpsResult, type BundlePoolType, type BundleUserType, buildDexBatchBuyOps, buildDexBatchBuyOpsV3, type DexBatchBuyParams, type DexBatchBuyV3Params, type DexBatchBuyResult, buildDexBatchSellOps, buildDexBatchSellOpsV3, type DexBatchSellParams, type DexBatchSellV3Params, type DexBatchSellResult, buildDisperseFromSingleOwnerOpsWithProfit, buildTransfersWithProfit, createAAAccountManager as xlayerCreateAAAccountManager, predictSender as xlayerPredictSender, createWallet as xlayerCreateWallet, AAAccountManager as XLayerAAAccountManager, generateAAWallets as xlayerGenerateAAWallets, generateAAWalletsFromMnemonic as xlayerGenerateAAWalletsFromMnemonic, predictSendersFromPrivateKeys as xlayerPredictSendersFromPrivateKeys, createBundlerClient as xlayerCreateBundlerClient, BundlerClient as XLayerBundlerClient, createPortalQuery as xlayerCreatePortalQuery, PortalQuery as XLayerPortalQuery, encodeBuyCall as xlayerEncodeBuyCall, encodeSellCall as xlayerEncodeSellCall, encodeApproveCall as xlayerEncodeApproveCall, parseOkb as xlayerParseOkb, formatOkb as xlayerFormatOkb, XLAYER_CHAIN_ID, FLAP_PORTAL as XLAYER_FLAP_PORTAL, ENTRYPOINT_V06 as XLAYER_ENTRYPOINT, SIMPLE_ACCOUNT_FACTORY as XLAYER_FACTORY, PARTICLE_BUNDLER_URL as XLAYER_BUNDLER_URL, WOKB as XLAYER_WOKB, POTATOSWAP_V2_ROUTER as XLAYER_POTATOSWAP_ROUTER, type XLayerConfig, type BundleBuyParams as XLayerBundleBuyParams, type BundleSellParams as XLayerBundleSellParams, type BundleBuySellParams as XLayerBundleBuySellParams, type BundleSwapParams as XLayerBundleSwapParams, type BundleSwapSignParams as XLayerBundleSwapSignParams, type BundleBatchSwapParams as XLayerBundleBatchSwapParams, type BundleBatchSwapSignParams as XLayerBundleBatchSwapSignParams, type VolumeParams as XLayerVolumeParams, type BundleBuyResult as XLayerBundleBuyResult, type BundleSellResult as XLayerBundleSellResult, type BundleBuySellResult as XLayerBundleBuySellResult, type BundleCreateBuySignParams as XLayerBundleCreateBuySignParams, type BundleCreateBuySignResult as XLayerBundleCreateBuySignResult, type BundleCreateToDexSignParams as XLayerBundleCreateToDexSignParams, type BundleCreateToDexSignResult as XLayerBundleCreateToDexSignResult, type BundleGraduateBuyParams as XLayerBundleGraduateBuyParams, type BundleGraduateBuyResult as XLayerBundleGraduateBuyResult, type BundleSwapResult as XLayerBundleSwapResult, type BundleSwapSignResult as XLayerBundleSwapSignResult, type BundleBatchSwapResult as XLayerBundleBatchSwapResult, type BundleBatchSwapSignResult as XLayerBundleBatchSwapSignResult, type VolumeResult as XLayerVolumeResult, xlayerQuickBatchSwapMerkle, xlayerCrossSwapMerkle,
|
|
57
|
+
export { bundleBuy as xlayerBundleBuy, bundleSell as xlayerBundleSell, bundleBuySell as xlayerBundleBuySell, bundleCreateBuySign as xlayerBundleCreateBuySign, bundleCreateToDexSign as xlayerBundleCreateToDexSign, bundleGraduateBuy as xlayerBundleGraduateBuy, bundleSwapSign as xlayerBundleSwapSign, bundleBatchSwapSign as xlayerBundleBatchSwapSign, createBundleExecutor as xlayerCreateBundleExecutor, BundleExecutor as XLayerBundleExecutor, makeVolume as xlayerMakeVolume, singleRoundVolume as xlayerSingleRoundVolume, createVolumeExecutor as xlayerCreateVolumeExecutor, VolumeExecutor as XLayerVolumeExecutor, makeBuyFirstVolume as xlayerMakeBuyFirstVolume, BuyFirstVolumeExecutor as XLayerBuyFirstVolumeExecutor, AAPortalBuyFirstExecutor as XLayerAAPortalBuyFirstExecutor, AADexBuyFirstExecutor as XLayerAADexBuyFirstExecutor, AAVolumeBuyFirstExecutor as XLayerAAVolumeBuyFirstExecutor, createAAVolumeBuyFirstExecutor as xlayerCreateAAVolumeBuyFirstExecutor, type VolumeBuyFirstParams as XLayerVolumeBuyFirstParams, type VolumeBuyFirstResult as XLayerVolumeBuyFirstResult, type VolumeContinuousParams as XLayerVolumeContinuousParams, type VolumeContinuousResult as XLayerVolumeContinuousResult, type VolumeProgress as XLayerVolumeProgress, createDexExecutor as xlayerCreateDexExecutor, createDexQuery as xlayerCreateDexQuery, quoteOkbToToken as xlayerQuoteOkbToToken, quoteTokenToOkb as xlayerQuoteTokenToOkb, DexExecutor as XLayerDexExecutor, DexQuery as XLayerDexQuery, buildWashOps, type WashOpsParams, type WashOpsResult, type WashPoolType, type WashUserType, buildBundleBuyOps, buildBundleSellOps, buildBundleProfitOp, filterOutProfitOps, type BundleBuyOpsParams, type BundleSellOpsParams, type BundleProfitOpParams, type BundleOpsResult, type BundlePoolType, type BundleUserType, buildDexBatchBuyOps, buildDexBatchBuyOpsV3, type DexBatchBuyParams, type DexBatchBuyV3Params, type DexBatchBuyResult, buildDexBatchSellOps, buildDexBatchSellOpsV3, type DexBatchSellParams, type DexBatchSellV3Params, type DexBatchSellResult, buildDisperseFromSingleOwnerOpsWithProfit, buildTransfersWithProfit, createAAAccountManager as xlayerCreateAAAccountManager, predictSender as xlayerPredictSender, createWallet as xlayerCreateWallet, AAAccountManager as XLayerAAAccountManager, generateAAWallets as xlayerGenerateAAWallets, generateAAWalletsFromMnemonic as xlayerGenerateAAWalletsFromMnemonic, predictSendersFromPrivateKeys as xlayerPredictSendersFromPrivateKeys, createBundlerClient as xlayerCreateBundlerClient, BundlerClient as XLayerBundlerClient, createPortalQuery as xlayerCreatePortalQuery, PortalQuery as XLayerPortalQuery, encodeBuyCall as xlayerEncodeBuyCall, encodeSellCall as xlayerEncodeSellCall, encodeApproveCall as xlayerEncodeApproveCall, parseOkb as xlayerParseOkb, formatOkb as xlayerFormatOkb, XLAYER_CHAIN_ID, FLAP_PORTAL as XLAYER_FLAP_PORTAL, ENTRYPOINT_V06 as XLAYER_ENTRYPOINT, SIMPLE_ACCOUNT_FACTORY as XLAYER_FACTORY, PARTICLE_BUNDLER_URL as XLAYER_BUNDLER_URL, WOKB as XLAYER_WOKB, POTATOSWAP_V2_ROUTER as XLAYER_POTATOSWAP_ROUTER, type XLayerConfig, type BundleBuyParams as XLayerBundleBuyParams, type BundleSellParams as XLayerBundleSellParams, type BundleBuySellParams as XLayerBundleBuySellParams, type BundleSwapParams as XLayerBundleSwapParams, type BundleSwapSignParams as XLayerBundleSwapSignParams, type BundleBatchSwapParams as XLayerBundleBatchSwapParams, type BundleBatchSwapSignParams as XLayerBundleBatchSwapSignParams, type VolumeParams as XLayerVolumeParams, type BundleBuyResult as XLayerBundleBuyResult, type BundleSellResult as XLayerBundleSellResult, type BundleBuySellResult as XLayerBundleBuySellResult, type BundleCreateBuySignParams as XLayerBundleCreateBuySignParams, type BundleCreateBuySignResult as XLayerBundleCreateBuySignResult, type BundleCreateToDexSignParams as XLayerBundleCreateToDexSignParams, type BundleCreateToDexSignResult as XLayerBundleCreateToDexSignResult, type BundleGraduateBuyParams as XLayerBundleGraduateBuyParams, type BundleGraduateBuyResult as XLayerBundleGraduateBuyResult, type BundleSwapResult as XLayerBundleSwapResult, type BundleSwapSignResult as XLayerBundleSwapSignResult, type BundleBatchSwapResult as XLayerBundleBatchSwapResult, type BundleBatchSwapSignResult as XLayerBundleBatchSwapSignResult, type VolumeResult as XLayerVolumeResult, xlayerQuickBatchSwapMerkle, xlayerCrossSwapMerkle, xlayerPureCrossSwapMerkle, // ✅ 真正的交叉换手(无资金转移)
|
|
58
|
+
type XLayerEoaSwapConfig, type XLayerQuickBatchSwapParams, type XLayerQuickBatchSwapResult, type XLayerCrossSwapParams, type XLayerCrossSwapResult, type XLayerPureCrossSwapParams, // ✅ 真正的交叉换手参数
|
|
59
|
+
type XLayerPureCrossSwapResult, // ✅ 真正的交叉换手结果
|
|
60
|
+
type BuyFirstParams as XLayerBuyFirstParams, type BuyFirstResult as XLayerBuyFirstResult, type BuyFirstVolumeParams as XLayerBuyFirstVolumeParams, type BuyFirstVolumeResult as XLayerBuyFirstVolumeResult, type HandleOpsResult as XLayerHandleOpsResult, type AAAccount as XLayerAAAccount, type UserOperation as XLayerUserOperation, type GeneratedAAWallet as XLayerGeneratedAAWallet, type GenerateAAWalletsParams as XLayerGenerateAAWalletsParams, type GenerateAAWalletsResult as XLayerGenerateAAWalletsResult, } from './xlayer/index.js';
|
|
58
61
|
export * as XLayerBundle from './eip7702/xlayer/index.js';
|
|
59
62
|
export { XLayerBundle as XLayerType4BundleExecutor, createBundle as xlayerType4BundleCreate, bundleBatchApprove as xlayerBundleBatchApprove, bundleBatchBuy as xlayerBundleBatchBuy, bundleBatchSell as xlayerBundleBatchSell, checkApprovalStatus as xlayerBundleCheckApproval, checkApprovalStatusBatch as xlayerBundleCheckApprovalBatch, buildApprove as xlayerBundleBuildApprove, buildTransfer as xlayerBundleBuildTransfer, buildNativeTransfer as xlayerBundleBuildNativeTransfer, buildV2SwapBuy as xlayerBundleBuildV2SwapBuy, buildV2SwapSell as xlayerBundleBuildV2SwapSell, collectProfit as xlayerBundleCollectProfit, collectProfitBatch as xlayerBundleCollectProfitBatch, collectProfitFromTrade as xlayerBundleCollectProfitFromTrade, calculateProfit as xlayerBundleCalculateProfit, getProfitRateBps as xlayerBundleGetProfitRateBps, getProfitRecipient as xlayerBundleGetProfitRecipient, EXECUTOR_ADDRESS as XLAYER_BUNDLE_EXECUTOR_ADDRESS, SPENDERS_TO_APPROVE as XLAYER_BUNDLE_SPENDERS, XLAYER_PROFIT_CONFIG, type BundleParticipant as XLayerBundleParticipant, type BatchApproveParams as XLayerBundleBatchApproveParams, type BatchBuyParams as XLayerBundleBatchBuyParams, type BatchSellParams as XLayerBundleBatchSellParams, type BatchOperationResult as XLayerBundleBatchOperationResult, type BundleResult as XLayerBundleResult, type Call as XLayerBundleCall, type UserType as XLayerBundleUserType, type ProfitMode as XLayerBundleProfitMode, type ProfitParams as XLayerBundleProfitParams, type ProfitResult as XLayerBundleProfitResult, signBatchApprove as xlayerBundleSignBatchApprove, signBatchBuy as xlayerBundleSignBatchBuy, signBatchSell as xlayerBundleSignBatchSell, signCustomCalls as xlayerBundleSignCustomCalls, type SignConfig as XLayerBundleSignConfig, type SignedTransaction as XLayerBundleSignedTransaction, broadcastSignedBundle as xlayerBundleBroadcast, broadcastSignedBundleBatch as xlayerBundleBroadcastBatch, submitBundleToXLayer as xlayerBundleSubmit, type BroadcastConfig as XLayerBundleBroadcastConfig, type BroadcastResult as XLayerBundleBroadcastResult, signCreateToDex as xlayerBundleSignCreateToDex, type CreateTokenInfo as XLayerBundleCreateTokenInfo, type CreateToDexParams as XLayerBundleCreateToDexParams, type CreateToDexSignedResult as XLayerBundleCreateToDexResult, signCurveToDex as xlayerBundleSignCurveToDex, type CurveToDexParams as XLayerBundleCurveToDexParams, type CurveToDexSignedResult as XLayerBundleCurveToDexResult, signDisperseNative as xlayerBundleSignDisperseNative, signDisperseERC20 as xlayerBundleSignDisperseERC20, signDisperseNativeWithAutoHop as xlayerBundleSignDisperseNativeWithAutoHop, type DisperseNativeParams as XLayerBundleDisperseNativeParams, type DisperseERC20Params as XLayerBundleDisperseERC20Params, type DisperseSignedResult as XLayerBundleDisperseResult, signSweepNative as xlayerBundleSignSweepNative, signSweepERC20 as xlayerBundleSignSweepERC20, signSweepNativeWithAutoHop as xlayerBundleSignSweepNativeWithAutoHop, type SweepNativeParams as XLayerBundleSweepNativeParams, type SweepERC20Params as XLayerBundleSweepERC20Params, type SweepSignedResult as XLayerBundleSweepResult, } from './eip7702/xlayer/index.js';
|
package/dist/index.js
CHANGED
|
@@ -135,7 +135,8 @@ parseOkb as xlayerParseOkb, formatOkb as xlayerFormatOkb,
|
|
|
135
135
|
// 常量
|
|
136
136
|
XLAYER_CHAIN_ID, FLAP_PORTAL as XLAYER_FLAP_PORTAL, ENTRYPOINT_V06 as XLAYER_ENTRYPOINT, SIMPLE_ACCOUNT_FACTORY as XLAYER_FACTORY, PARTICLE_BUNDLER_URL as XLAYER_BUNDLER_URL, WOKB as XLAYER_WOKB, POTATOSWAP_V2_ROUTER as XLAYER_POTATOSWAP_ROUTER,
|
|
137
137
|
// ✅ XLayer EOA 模式换手(不影响 BSC 链)
|
|
138
|
-
xlayerQuickBatchSwapMerkle, xlayerCrossSwapMerkle,
|
|
138
|
+
xlayerQuickBatchSwapMerkle, xlayerCrossSwapMerkle, xlayerPureCrossSwapMerkle, // ✅ 真正的交叉换手(无资金转移)
|
|
139
|
+
} from './xlayer/index.js';
|
|
139
140
|
// ============================================================
|
|
140
141
|
// ✅ XLayer Bundle 模式
|
|
141
142
|
// ============================================================
|
|
@@ -95,3 +95,49 @@ export interface XLayerCrossSwapResult {
|
|
|
95
95
|
}
|
|
96
96
|
export declare function xlayerQuickBatchSwapMerkle(params: XLayerQuickBatchSwapParams): Promise<XLayerQuickBatchSwapResult>;
|
|
97
97
|
export declare function xlayerCrossSwapMerkle(params: XLayerCrossSwapParams): Promise<XLayerCrossSwapResult>;
|
|
98
|
+
/**
|
|
99
|
+
* 真正的交叉换手参数
|
|
100
|
+
*/
|
|
101
|
+
export interface XLayerPureCrossSwapParams {
|
|
102
|
+
/** 卖方私钥列表 */
|
|
103
|
+
sellerPrivateKeys: string[];
|
|
104
|
+
/** 每个卖方的卖出数量 */
|
|
105
|
+
sellAmounts: string[];
|
|
106
|
+
/** 买方私钥列表 */
|
|
107
|
+
buyerPrivateKeys: string[];
|
|
108
|
+
/** 每个买方的买入 OKB 数量 */
|
|
109
|
+
buyAmounts: string[];
|
|
110
|
+
/** 代币地址 */
|
|
111
|
+
tokenAddress: string;
|
|
112
|
+
/** 路由参数 */
|
|
113
|
+
routeParams: RouteParams;
|
|
114
|
+
/** 配置 */
|
|
115
|
+
config: XLayerEoaSwapConfig;
|
|
116
|
+
/** 报价代币(默认 OKB) */
|
|
117
|
+
quoteToken?: string;
|
|
118
|
+
/** 预获取的 nonce(地址 -> nonce) */
|
|
119
|
+
startNonces?: Map<string, number>;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* 真正的交叉换手结果
|
|
123
|
+
*/
|
|
124
|
+
export interface XLayerPureCrossSwapResult {
|
|
125
|
+
signedTransactions: string[];
|
|
126
|
+
metadata: {
|
|
127
|
+
sellerAddresses: string[];
|
|
128
|
+
buyerAddresses: string[];
|
|
129
|
+
sellAmounts: string[];
|
|
130
|
+
buyAmounts: string[];
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* ✅ 真正的交叉换手
|
|
135
|
+
*
|
|
136
|
+
* 与资金利用率模式不同:
|
|
137
|
+
* - 卖方卖出代币 → OKB 留在卖方钱包
|
|
138
|
+
* - 买方用自己的 OKB 买入代币
|
|
139
|
+
* - 无资金转移
|
|
140
|
+
*
|
|
141
|
+
* 交易顺序:卖1 → 买1 → 卖2 → 买2 → ... (交替执行)
|
|
142
|
+
*/
|
|
143
|
+
export declare function xlayerPureCrossSwapMerkle(params: XLayerPureCrossSwapParams): Promise<XLayerPureCrossSwapResult>;
|
|
@@ -594,3 +594,164 @@ export async function xlayerCrossSwapMerkle(params) {
|
|
|
594
594
|
profitHopWallets: allProfit.length > 0 ? allProfit : undefined
|
|
595
595
|
};
|
|
596
596
|
}
|
|
597
|
+
/**
|
|
598
|
+
* ✅ 真正的交叉换手
|
|
599
|
+
*
|
|
600
|
+
* 与资金利用率模式不同:
|
|
601
|
+
* - 卖方卖出代币 → OKB 留在卖方钱包
|
|
602
|
+
* - 买方用自己的 OKB 买入代币
|
|
603
|
+
* - 无资金转移
|
|
604
|
+
*
|
|
605
|
+
* 交易顺序:卖1 → 买1 → 卖2 → 买2 → ... (交替执行)
|
|
606
|
+
*/
|
|
607
|
+
export async function xlayerPureCrossSwapMerkle(params) {
|
|
608
|
+
const { sellerPrivateKeys, sellAmounts, buyerPrivateKeys, buyAmounts, tokenAddress, routeParams, config, quoteToken, startNonces: inputNonces } = params;
|
|
609
|
+
if (sellerPrivateKeys.length === 0)
|
|
610
|
+
throw new Error('至少需要一个卖方');
|
|
611
|
+
if (sellerPrivateKeys.length !== sellAmounts.length)
|
|
612
|
+
throw new Error('sellAmounts 长度必须与卖方数量一致');
|
|
613
|
+
if (buyerPrivateKeys.length === 0)
|
|
614
|
+
throw new Error('至少需要一个买方');
|
|
615
|
+
if (buyerPrivateKeys.length !== buyAmounts.length)
|
|
616
|
+
throw new Error('buyAmounts 长度必须与买方数量一致');
|
|
617
|
+
const context = createXLayerContext(config);
|
|
618
|
+
const nonceManager = new NonceManager(context.provider);
|
|
619
|
+
const useNativeToken = !quoteToken || quoteToken === ZERO_ADDRESS;
|
|
620
|
+
const sellers = sellerPrivateKeys.map(pk => new Wallet(pk, context.provider));
|
|
621
|
+
const buyers = buyerPrivateKeys.map(pk => new Wallet(pk, context.provider));
|
|
622
|
+
// 获取 nonce
|
|
623
|
+
const addressToNonce = new Map();
|
|
624
|
+
for (const wallet of [...sellers, ...buyers]) {
|
|
625
|
+
if (!addressToNonce.has(wallet.address)) {
|
|
626
|
+
const inputNonce = inputNonces?.get(wallet.address.toLowerCase()) ?? inputNonces?.get(wallet.address);
|
|
627
|
+
if (inputNonce !== undefined) {
|
|
628
|
+
addressToNonce.set(wallet.address, inputNonce);
|
|
629
|
+
}
|
|
630
|
+
else {
|
|
631
|
+
addressToNonce.set(wallet.address, await nonceManager.getNextNonce(wallet));
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
const [gasPrice, finalGasLimit] = await Promise.all([
|
|
636
|
+
getGasPrice(context.provider, config),
|
|
637
|
+
Promise.resolve(getGasLimit(config))
|
|
638
|
+
]);
|
|
639
|
+
const txType = config.txType ?? 0;
|
|
640
|
+
const deadline = getDeadline();
|
|
641
|
+
const v3RouterIface = new ethers.Interface(V3_ROUTER02_ABI);
|
|
642
|
+
const signedTransactions = [];
|
|
643
|
+
console.log(`[xlayerPureCrossSwap] 真正的交叉换手: ${sellers.length} 卖方, ${buyers.length} 买方`);
|
|
644
|
+
// ==================== 卖出交易 ====================
|
|
645
|
+
for (let i = 0; i < sellers.length; i++) {
|
|
646
|
+
const seller = sellers[i];
|
|
647
|
+
const sellAmount = sellAmounts[i];
|
|
648
|
+
const nonce = addressToNonce.get(seller.address);
|
|
649
|
+
addressToNonce.set(seller.address, nonce + 1);
|
|
650
|
+
// 计算卖出数量
|
|
651
|
+
const { amount: sellAmountWei, decimals } = await calculateSellAmount(context.provider, tokenAddress, seller.address, sellAmount);
|
|
652
|
+
console.log(`[xlayerPureCrossSwap] 卖方 ${i + 1}: ${seller.address.slice(0, 10)}... 卖出 ${ethers.formatUnits(sellAmountWei, decimals)}`);
|
|
653
|
+
let sellUnsigned;
|
|
654
|
+
if (routeParams.routeType === 'v2') {
|
|
655
|
+
const { v2Path } = routeParams;
|
|
656
|
+
const v2Router = new Contract(POTATO_V2_ROUTER, V2_ROUTER_ABI, seller);
|
|
657
|
+
if (useNativeToken) {
|
|
658
|
+
sellUnsigned = await v2Router.swapExactTokensForETHSupportingFeeOnTransferTokens.populateTransaction(sellAmountWei, 0n, v2Path, seller.address, deadline);
|
|
659
|
+
}
|
|
660
|
+
else {
|
|
661
|
+
sellUnsigned = await v2Router.swapExactTokensForTokensSupportingFeeOnTransferTokens.populateTransaction(sellAmountWei, 0n, v2Path, seller.address, deadline);
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
else if (routeParams.routeType === 'v3-single') {
|
|
665
|
+
const { v3TokenIn, v3TokenOut, v3Fee } = routeParams;
|
|
666
|
+
const v3Router = new Contract(POTATO_V3_ROUTER, V3_ROUTER02_ABI, seller);
|
|
667
|
+
const sellSwapData = v3RouterIface.encodeFunctionData('exactInputSingle', [{
|
|
668
|
+
tokenIn: v3TokenIn,
|
|
669
|
+
tokenOut: v3TokenOut,
|
|
670
|
+
fee: v3Fee,
|
|
671
|
+
recipient: useNativeToken ? POTATO_V3_ROUTER : seller.address,
|
|
672
|
+
amountIn: sellAmountWei,
|
|
673
|
+
amountOutMinimum: 0n,
|
|
674
|
+
sqrtPriceLimitX96: 0n
|
|
675
|
+
}]);
|
|
676
|
+
if (useNativeToken) {
|
|
677
|
+
const sellUnwrapData = v3RouterIface.encodeFunctionData('unwrapWETH9', [0n, seller.address]);
|
|
678
|
+
sellUnsigned = await v3Router.multicall.populateTransaction(deadline, [sellSwapData, sellUnwrapData]);
|
|
679
|
+
}
|
|
680
|
+
else {
|
|
681
|
+
sellUnsigned = await v3Router.multicall.populateTransaction(deadline, [sellSwapData]);
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
else {
|
|
685
|
+
throw new Error('V3 多跳路由暂不支持');
|
|
686
|
+
}
|
|
687
|
+
const signedSell = await seller.signTransaction({
|
|
688
|
+
...sellUnsigned,
|
|
689
|
+
from: seller.address,
|
|
690
|
+
nonce,
|
|
691
|
+
gasLimit: finalGasLimit,
|
|
692
|
+
gasPrice,
|
|
693
|
+
chainId: XLAYER_CHAIN_ID,
|
|
694
|
+
type: txType
|
|
695
|
+
});
|
|
696
|
+
signedTransactions.push(signedSell);
|
|
697
|
+
}
|
|
698
|
+
// ==================== 买入交易 ====================
|
|
699
|
+
for (let i = 0; i < buyers.length; i++) {
|
|
700
|
+
const buyer = buyers[i];
|
|
701
|
+
const buyAmount = buyAmounts[i];
|
|
702
|
+
const nonce = addressToNonce.get(buyer.address);
|
|
703
|
+
addressToNonce.set(buyer.address, nonce + 1);
|
|
704
|
+
const buyAmountWei = ethers.parseEther(buyAmount);
|
|
705
|
+
const buyValue = useNativeToken ? buyAmountWei : 0n;
|
|
706
|
+
console.log(`[xlayerPureCrossSwap] 买方 ${i + 1}: ${buyer.address.slice(0, 10)}... 买入 ${buyAmount} OKB`);
|
|
707
|
+
let buyUnsigned;
|
|
708
|
+
if (routeParams.routeType === 'v2') {
|
|
709
|
+
const { v2Path } = routeParams;
|
|
710
|
+
const reversePath = [...v2Path].reverse();
|
|
711
|
+
const v2Router = new Contract(POTATO_V2_ROUTER, V2_ROUTER_ABI, buyer);
|
|
712
|
+
if (useNativeToken) {
|
|
713
|
+
buyUnsigned = await v2Router.swapExactETHForTokensSupportingFeeOnTransferTokens.populateTransaction(0n, reversePath, buyer.address, deadline, { value: buyValue });
|
|
714
|
+
}
|
|
715
|
+
else {
|
|
716
|
+
buyUnsigned = await v2Router.swapExactTokensForTokensSupportingFeeOnTransferTokens.populateTransaction(buyAmountWei, 0n, reversePath, buyer.address, deadline);
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
else if (routeParams.routeType === 'v3-single') {
|
|
720
|
+
const { v3TokenIn, v3TokenOut, v3Fee } = routeParams;
|
|
721
|
+
const v3Router = new Contract(POTATO_V3_ROUTER, V3_ROUTER02_ABI, buyer);
|
|
722
|
+
const buySwapData = v3RouterIface.encodeFunctionData('exactInputSingle', [{
|
|
723
|
+
tokenIn: v3TokenOut, // 买入时反过来
|
|
724
|
+
tokenOut: v3TokenIn,
|
|
725
|
+
fee: v3Fee,
|
|
726
|
+
recipient: buyer.address,
|
|
727
|
+
amountIn: buyAmountWei,
|
|
728
|
+
amountOutMinimum: 0n,
|
|
729
|
+
sqrtPriceLimitX96: 0n
|
|
730
|
+
}]);
|
|
731
|
+
buyUnsigned = await v3Router.multicall.populateTransaction(deadline, [buySwapData], { value: buyValue });
|
|
732
|
+
}
|
|
733
|
+
else {
|
|
734
|
+
throw new Error('V3 多跳路由暂不支持');
|
|
735
|
+
}
|
|
736
|
+
const signedBuy = await buyer.signTransaction({
|
|
737
|
+
...buyUnsigned,
|
|
738
|
+
from: buyer.address,
|
|
739
|
+
nonce,
|
|
740
|
+
gasLimit: finalGasLimit,
|
|
741
|
+
gasPrice,
|
|
742
|
+
chainId: XLAYER_CHAIN_ID,
|
|
743
|
+
type: txType
|
|
744
|
+
});
|
|
745
|
+
signedTransactions.push(signedBuy);
|
|
746
|
+
}
|
|
747
|
+
console.log(`[xlayerPureCrossSwap] 完成: ${signedTransactions.length} 笔交易 (${sellers.length} 卖 + ${buyers.length} 买)`);
|
|
748
|
+
return {
|
|
749
|
+
signedTransactions,
|
|
750
|
+
metadata: {
|
|
751
|
+
sellerAddresses: sellers.map(s => s.address),
|
|
752
|
+
buyerAddresses: buyers.map(b => b.address),
|
|
753
|
+
sellAmounts,
|
|
754
|
+
buyAmounts
|
|
755
|
+
}
|
|
756
|
+
};
|
|
757
|
+
}
|
package/dist/xlayer/index.d.ts
CHANGED
|
@@ -92,7 +92,10 @@ export { buildDexBatchSellOps, buildDexBatchSellOpsV3, type DexBatchSellParams,
|
|
|
92
92
|
export { buildDisperseFromSingleOwnerOpsWithProfit, buildTransfersWithProfit, } from './aa-transfer-profit.js';
|
|
93
93
|
export { buildWashOps, type WashOpsParams, type WashOpsResult, type WashPoolType, type WashUserType, } from './wash-ops.js';
|
|
94
94
|
export { buildBundleBuyOps, buildBundleSellOps, buildBundleProfitOp, filterOutProfitOps, type BundleBuyOpsParams, type BundleSellOpsParams, type BundleProfitOpParams, type BundleOpsResult, type BundlePoolType, type BundleUserType, } from './bundle-buy-first.js';
|
|
95
|
-
export { xlayerQuickBatchSwapMerkle, xlayerCrossSwapMerkle,
|
|
95
|
+
export { xlayerQuickBatchSwapMerkle, xlayerCrossSwapMerkle, xlayerPureCrossSwapMerkle, // ✅ 真正的交叉换手(无资金转移)
|
|
96
|
+
type XLayerEoaSwapConfig, type XLayerQuickBatchSwapParams, type XLayerQuickBatchSwapResult, type XLayerCrossSwapParams, type XLayerCrossSwapResult, type XLayerPureCrossSwapParams, // ✅ 真正的交叉换手参数
|
|
97
|
+
type XLayerPureCrossSwapResult, // ✅ 真正的交叉换手结果
|
|
98
|
+
type UserType as XLayerUserType, type RouteParams as XLayerRouteParams, type V2RouteParams as XLayerV2RouteParams, type V3SingleRouteParams as XLayerV3SingleRouteParams, } from './eoa-bundle-swap.js';
|
|
96
99
|
export declare const xlayer: {
|
|
97
100
|
bundleBuy: (params: import("./types.js").BundleBuyParams) => Promise<import("./types.js").BundleBuyResult>;
|
|
98
101
|
bundleSell: (params: import("./types.js").BundleSellParams) => Promise<import("./types.js").BundleSellResult>;
|
package/dist/xlayer/index.js
CHANGED
|
@@ -174,7 +174,8 @@ export { buildBundleBuyOps, buildBundleSellOps, buildBundleProfitOp, filterOutPr
|
|
|
174
174
|
// ============================================================================
|
|
175
175
|
// ✅ XLayer EOA 模式换手(不影响 BSC 链)
|
|
176
176
|
// ============================================================================
|
|
177
|
-
export { xlayerQuickBatchSwapMerkle, xlayerCrossSwapMerkle,
|
|
177
|
+
export { xlayerQuickBatchSwapMerkle, xlayerCrossSwapMerkle, xlayerPureCrossSwapMerkle, // ✅ 真正的交叉换手(无资金转移)
|
|
178
|
+
} from './eoa-bundle-swap.js';
|
|
178
179
|
// ============================================================================
|
|
179
180
|
// 便捷重导出
|
|
180
181
|
// ============================================================================
|
package/package.json
CHANGED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ECDH + AES-GCM 加密工具(浏览器兼容)
|
|
3
|
-
* 用于将签名交易用服务器公钥加密
|
|
4
|
-
*/
|
|
5
|
-
/**
|
|
6
|
-
* 用服务器公钥加密签名交易(ECDH + AES-GCM)
|
|
7
|
-
*
|
|
8
|
-
* @param signedTransactions 签名后的交易数组
|
|
9
|
-
* @param publicKeyBase64 服务器提供的公钥(Base64 格式)
|
|
10
|
-
* @returns JSON 字符串 {e: 临时公钥, i: IV, d: 密文}
|
|
11
|
-
*/
|
|
12
|
-
export declare function encryptWithPublicKey(signedTransactions: string[], publicKeyBase64: string): Promise<string>;
|
|
13
|
-
/**
|
|
14
|
-
* 验证公钥格式(Base64)
|
|
15
|
-
*/
|
|
16
|
-
export declare function validatePublicKey(publicKeyBase64: string): boolean;
|
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ECDH + AES-GCM 加密工具(浏览器兼容)
|
|
3
|
-
* 用于将签名交易用服务器公钥加密
|
|
4
|
-
*/
|
|
5
|
-
/**
|
|
6
|
-
* 获取全局 crypto 对象(最简单直接的方式)
|
|
7
|
-
*/
|
|
8
|
-
function getCryptoAPI() {
|
|
9
|
-
// 尝试所有可能的全局对象,优先浏览器环境
|
|
10
|
-
const cryptoObj = (typeof window !== 'undefined' && window.crypto) ||
|
|
11
|
-
(typeof self !== 'undefined' && self.crypto) ||
|
|
12
|
-
(typeof global !== 'undefined' && global.crypto) ||
|
|
13
|
-
(typeof globalThis !== 'undefined' && globalThis.crypto);
|
|
14
|
-
if (!cryptoObj) {
|
|
15
|
-
const env = typeof window !== 'undefined' ? 'Browser' : 'Node.js';
|
|
16
|
-
const protocol = typeof location !== 'undefined' ? location.protocol : 'unknown';
|
|
17
|
-
throw new Error(`❌ Crypto API 不可用。环境: ${env}, 协议: ${protocol}. ` +
|
|
18
|
-
'请确保在 HTTPS 或 localhost 下运行');
|
|
19
|
-
}
|
|
20
|
-
return cryptoObj;
|
|
21
|
-
}
|
|
22
|
-
/**
|
|
23
|
-
* 获取 SubtleCrypto(用于加密操作)
|
|
24
|
-
*/
|
|
25
|
-
function getSubtleCrypto() {
|
|
26
|
-
const crypto = getCryptoAPI();
|
|
27
|
-
if (!crypto.subtle) {
|
|
28
|
-
const protocol = typeof location !== 'undefined' ? location.protocol : 'unknown';
|
|
29
|
-
const hostname = typeof location !== 'undefined' ? location.hostname : 'unknown';
|
|
30
|
-
throw new Error(`❌ SubtleCrypto API 不可用。协议: ${protocol}, 主机: ${hostname}. ` +
|
|
31
|
-
'请确保:1) 使用 HTTPS (或 localhost);2) 浏览器支持 Web Crypto API;' +
|
|
32
|
-
'3) 不在无痕/隐私浏览模式下');
|
|
33
|
-
}
|
|
34
|
-
return crypto.subtle;
|
|
35
|
-
}
|
|
36
|
-
/**
|
|
37
|
-
* Base64 转 ArrayBuffer(优先使用浏览器 API)
|
|
38
|
-
*/
|
|
39
|
-
function base64ToArrayBuffer(base64) {
|
|
40
|
-
// 浏览器环境(优先)
|
|
41
|
-
if (typeof atob !== 'undefined') {
|
|
42
|
-
const binaryString = atob(base64);
|
|
43
|
-
const bytes = new Uint8Array(binaryString.length);
|
|
44
|
-
for (let i = 0; i < binaryString.length; i++) {
|
|
45
|
-
bytes[i] = binaryString.charCodeAt(i);
|
|
46
|
-
}
|
|
47
|
-
return bytes.buffer;
|
|
48
|
-
}
|
|
49
|
-
// Node.js 环境(fallback)
|
|
50
|
-
if (typeof Buffer !== 'undefined') {
|
|
51
|
-
return Buffer.from(base64, 'base64').buffer;
|
|
52
|
-
}
|
|
53
|
-
throw new Error('❌ Base64 解码不可用');
|
|
54
|
-
}
|
|
55
|
-
/**
|
|
56
|
-
* ArrayBuffer 转 Base64(优先使用浏览器 API)
|
|
57
|
-
*/
|
|
58
|
-
function arrayBufferToBase64(buffer) {
|
|
59
|
-
// 浏览器环境(优先)
|
|
60
|
-
if (typeof btoa !== 'undefined') {
|
|
61
|
-
const bytes = new Uint8Array(buffer);
|
|
62
|
-
let binary = '';
|
|
63
|
-
for (let i = 0; i < bytes.length; i++) {
|
|
64
|
-
binary += String.fromCharCode(bytes[i]);
|
|
65
|
-
}
|
|
66
|
-
return btoa(binary);
|
|
67
|
-
}
|
|
68
|
-
// Node.js 环境(fallback)
|
|
69
|
-
if (typeof Buffer !== 'undefined') {
|
|
70
|
-
return Buffer.from(buffer).toString('base64');
|
|
71
|
-
}
|
|
72
|
-
throw new Error('❌ Base64 编码不可用');
|
|
73
|
-
}
|
|
74
|
-
/**
|
|
75
|
-
* 生成随机 Hex 字符串
|
|
76
|
-
*/
|
|
77
|
-
function randomHex(length) {
|
|
78
|
-
const crypto = getCryptoAPI();
|
|
79
|
-
const array = new Uint8Array(length);
|
|
80
|
-
crypto.getRandomValues(array);
|
|
81
|
-
return Array.from(array)
|
|
82
|
-
.map(b => b.toString(16).padStart(2, '0'))
|
|
83
|
-
.join('');
|
|
84
|
-
}
|
|
85
|
-
/**
|
|
86
|
-
* 用服务器公钥加密签名交易(ECDH + AES-GCM)
|
|
87
|
-
*
|
|
88
|
-
* @param signedTransactions 签名后的交易数组
|
|
89
|
-
* @param publicKeyBase64 服务器提供的公钥(Base64 格式)
|
|
90
|
-
* @returns JSON 字符串 {e: 临时公钥, i: IV, d: 密文}
|
|
91
|
-
*/
|
|
92
|
-
export async function encryptWithPublicKey(signedTransactions, publicKeyBase64) {
|
|
93
|
-
try {
|
|
94
|
-
// 0. 获取 SubtleCrypto 和 Crypto API
|
|
95
|
-
const subtle = getSubtleCrypto();
|
|
96
|
-
const crypto = getCryptoAPI();
|
|
97
|
-
// 1. 准备数据
|
|
98
|
-
const payload = {
|
|
99
|
-
signedTransactions,
|
|
100
|
-
timestamp: Date.now(),
|
|
101
|
-
nonce: randomHex(8)
|
|
102
|
-
};
|
|
103
|
-
const plaintext = JSON.stringify(payload);
|
|
104
|
-
// 2. 生成临时 ECDH 密钥对
|
|
105
|
-
const ephemeralKeyPair = await subtle.generateKey({ name: 'ECDH', namedCurve: 'P-256' }, true, ['deriveKey']);
|
|
106
|
-
// 3. 导入服务器公钥
|
|
107
|
-
const publicKeyBuffer = base64ToArrayBuffer(publicKeyBase64);
|
|
108
|
-
const publicKey = await subtle.importKey('raw', publicKeyBuffer, { name: 'ECDH', namedCurve: 'P-256' }, false, []);
|
|
109
|
-
// 4. 派生共享密钥(AES-256)
|
|
110
|
-
const sharedKey = await subtle.deriveKey({ name: 'ECDH', public: publicKey }, ephemeralKeyPair.privateKey, { name: 'AES-GCM', length: 256 }, false, ['encrypt']);
|
|
111
|
-
// 5. AES-GCM 加密
|
|
112
|
-
const iv = crypto.getRandomValues(new Uint8Array(12));
|
|
113
|
-
const encrypted = await subtle.encrypt({ name: 'AES-GCM', iv }, sharedKey, new TextEncoder().encode(plaintext));
|
|
114
|
-
// 6. 导出临时公钥
|
|
115
|
-
const ephemeralPublicKeyRaw = await subtle.exportKey('raw', ephemeralKeyPair.publicKey);
|
|
116
|
-
// 7. 返回加密包(JSON 格式)
|
|
117
|
-
return JSON.stringify({
|
|
118
|
-
e: arrayBufferToBase64(ephemeralPublicKeyRaw), // 临时公钥
|
|
119
|
-
i: arrayBufferToBase64(iv.buffer), // IV
|
|
120
|
-
d: arrayBufferToBase64(encrypted) // 密文
|
|
121
|
-
});
|
|
122
|
-
}
|
|
123
|
-
catch (error) {
|
|
124
|
-
throw new Error(`加密失败: ${error?.message || String(error)}`);
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
/**
|
|
128
|
-
* 验证公钥格式(Base64)
|
|
129
|
-
*/
|
|
130
|
-
export function validatePublicKey(publicKeyBase64) {
|
|
131
|
-
try {
|
|
132
|
-
if (!publicKeyBase64)
|
|
133
|
-
return false;
|
|
134
|
-
// Base64 字符集验证
|
|
135
|
-
if (!/^[A-Za-z0-9+/=]+$/.test(publicKeyBase64))
|
|
136
|
-
return false;
|
|
137
|
-
// ECDH P-256 公钥固定长度 65 字节(未压缩)
|
|
138
|
-
// Base64 编码后约 88 字符
|
|
139
|
-
if (publicKeyBase64.length < 80 || publicKeyBase64.length > 100)
|
|
140
|
-
return false;
|
|
141
|
-
return true;
|
|
142
|
-
}
|
|
143
|
-
catch {
|
|
144
|
-
return false;
|
|
145
|
-
}
|
|
146
|
-
}
|