four-flap-meme-sdk 1.6.7 → 1.6.9
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/index.d.ts +1 -1
- package/dist/index.js +2 -0
- package/dist/xlayer/aa-transfer-profit.d.ts +48 -0
- package/dist/xlayer/aa-transfer-profit.js +304 -0
- package/dist/xlayer/dex-aa-sell.js +118 -62
- package/dist/xlayer/index.d.ts +1 -0
- package/dist/xlayer/index.js +4 -0
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -54,4 +54,4 @@ 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, buildDexBatchBuyOps, buildDexBatchBuyOpsV3, type DexBatchBuyParams, type DexBatchBuyV3Params, type DexBatchBuyResult, buildDexBatchSellOps, buildDexBatchSellOpsV3, type DexBatchSellParams, type DexBatchSellV3Params, type DexBatchSellResult, 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, 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';
|
|
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, 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, 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';
|
package/dist/index.js
CHANGED
|
@@ -116,6 +116,8 @@ createDexExecutor as xlayerCreateDexExecutor, createDexQuery as xlayerCreateDexQ
|
|
|
116
116
|
buildDexBatchBuyOps, buildDexBatchBuyOpsV3,
|
|
117
117
|
// ✅ AA 批量卖出(安全版:利润配置硬编码在 SDK 内部)
|
|
118
118
|
buildDexBatchSellOps, buildDexBatchSellOpsV3,
|
|
119
|
+
// ✅ AA 分发/归集(安全版:利润配置硬编码在 SDK 内部)
|
|
120
|
+
buildDisperseFromSingleOwnerOpsWithProfit, buildTransfersWithProfit,
|
|
119
121
|
// AA 账户管理
|
|
120
122
|
createAAAccountManager as xlayerCreateAAAccountManager, predictSender as xlayerPredictSender, createWallet as xlayerCreateWallet, AAAccountManager as XLayerAAAccountManager,
|
|
121
123
|
// 批量生成钱包工具
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { XLayerConfig, UserOperation } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* ✅ XLayer AA:单一 owner 的 AA(Sender) 批量分发(SDK 安全版,内置利润)
|
|
4
|
+
* - native: execute(MULTICALL3, totalValue, aggregate3Value([...to + profitRecipient]))
|
|
5
|
+
* - erc20: execute(MULTICALL3, 0, aggregate3([...transfer(to) + transfer(profitRecipient)]))
|
|
6
|
+
*
|
|
7
|
+
* 安全:利润比例与接收者硬编码在 SDK 内部(PROFIT_CONFIG)。
|
|
8
|
+
* 规则:利润从“总分发金额”中扣除,不额外增加资金需求。
|
|
9
|
+
*/
|
|
10
|
+
export declare function buildDisperseFromSingleOwnerOpsWithProfit(params: {
|
|
11
|
+
kind: 'native' | 'erc20';
|
|
12
|
+
tokenAddress?: string;
|
|
13
|
+
tokenDecimals?: number;
|
|
14
|
+
ownerPrivateKey: string;
|
|
15
|
+
toAddresses: string[];
|
|
16
|
+
amounts: string[];
|
|
17
|
+
config?: Partial<XLayerConfig>;
|
|
18
|
+
senderAddress?: string;
|
|
19
|
+
startNonce?: bigint;
|
|
20
|
+
assumeDeployed?: boolean;
|
|
21
|
+
maxTransfersPerUserOp?: number;
|
|
22
|
+
}): Promise<{
|
|
23
|
+
ops: UserOperation[];
|
|
24
|
+
sender: string;
|
|
25
|
+
profitWei: bigint;
|
|
26
|
+
}>;
|
|
27
|
+
/**
|
|
28
|
+
* ✅ XLayer AA:多 owner 归集/转账(SDK 安全版,内置利润)
|
|
29
|
+
*
|
|
30
|
+
* 每个 owner 的 AA(Sender) 内部用 executeBatch 同时转账:
|
|
31
|
+
* - native:profitRecipient + toAddress(value 拆分)
|
|
32
|
+
* - erc20:token.transfer(profitRecipient) + token.transfer(toAddress)
|
|
33
|
+
*
|
|
34
|
+
* 安全:利润配置硬编码在 SDK 内部(PROFIT_CONFIG)。
|
|
35
|
+
*/
|
|
36
|
+
export declare function buildTransfersWithProfit(params: {
|
|
37
|
+
kind: 'native' | 'erc20';
|
|
38
|
+
tokenAddress?: string;
|
|
39
|
+
tokenDecimals?: number;
|
|
40
|
+
ownerPrivateKeys: string[];
|
|
41
|
+
toAddresses: string[];
|
|
42
|
+
amounts: string[];
|
|
43
|
+
config?: Partial<XLayerConfig>;
|
|
44
|
+
}): Promise<{
|
|
45
|
+
ops: UserOperation[];
|
|
46
|
+
senders: string[];
|
|
47
|
+
profitWei: bigint;
|
|
48
|
+
}>;
|
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
import { ethers } from 'ethers';
|
|
2
|
+
import { PROFIT_CONFIG } from '../utils/constants.js';
|
|
3
|
+
import { createAAAccountManager, createWallet, encodeExecute, encodeExecuteBatch } from './aa-account.js';
|
|
4
|
+
const MULTICALL3 = '0xca11bde05977b3631167028862be2a173976ca11';
|
|
5
|
+
function clampBps(bps) {
|
|
6
|
+
if (!Number.isFinite(bps))
|
|
7
|
+
return 0;
|
|
8
|
+
return Math.max(0, Math.min(10000, Math.floor(bps)));
|
|
9
|
+
}
|
|
10
|
+
function calcProfitWei(amountWei, bps) {
|
|
11
|
+
if (amountWei <= 0n)
|
|
12
|
+
return 0n;
|
|
13
|
+
const x = clampBps(bps);
|
|
14
|
+
if (x <= 0)
|
|
15
|
+
return 0n;
|
|
16
|
+
return (amountWei * BigInt(x)) / 10000n;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* ✅ XLayer AA:单一 owner 的 AA(Sender) 批量分发(SDK 安全版,内置利润)
|
|
20
|
+
* - native: execute(MULTICALL3, totalValue, aggregate3Value([...to + profitRecipient]))
|
|
21
|
+
* - erc20: execute(MULTICALL3, 0, aggregate3([...transfer(to) + transfer(profitRecipient)]))
|
|
22
|
+
*
|
|
23
|
+
* 安全:利润比例与接收者硬编码在 SDK 内部(PROFIT_CONFIG)。
|
|
24
|
+
* 规则:利润从“总分发金额”中扣除,不额外增加资金需求。
|
|
25
|
+
*/
|
|
26
|
+
export async function buildDisperseFromSingleOwnerOpsWithProfit(params) {
|
|
27
|
+
const effConfig = { ...(params.config ?? {}) };
|
|
28
|
+
const aaManager = createAAAccountManager(effConfig);
|
|
29
|
+
const provider = aaManager.getProvider();
|
|
30
|
+
const ownerWallet = createWallet(String(params.ownerPrivateKey), effConfig);
|
|
31
|
+
const toList = (params.toAddresses || []).map((a) => String(a || '').trim()).filter(Boolean);
|
|
32
|
+
const amtList = (params.amounts || []).map((a) => String(a || '').trim());
|
|
33
|
+
if (toList.length === 0)
|
|
34
|
+
return { ops: [], sender: '', profitWei: 0n };
|
|
35
|
+
if (toList.length !== amtList.length)
|
|
36
|
+
throw new Error('AA disperse:toAddresses 与 amounts 数量不一致');
|
|
37
|
+
for (const to of toList) {
|
|
38
|
+
if (!/^0x[a-fA-F0-9]{40}$/.test(to))
|
|
39
|
+
throw new Error(`AA disperse:to 地址不合法: ${to}`);
|
|
40
|
+
}
|
|
41
|
+
const hinted = String(params.senderAddress || '').trim();
|
|
42
|
+
const sender = hinted && /^0x[a-fA-F0-9]{40}$/.test(hinted)
|
|
43
|
+
? hinted
|
|
44
|
+
: await aaManager.predictSenderAddress(ownerWallet.address);
|
|
45
|
+
const entryPoint = aaManager.getEntryPoint?.() || aaManager.entryPoint;
|
|
46
|
+
if (!entryPoint)
|
|
47
|
+
throw new Error('AA disperse:无法获取 EntryPoint 合约实例');
|
|
48
|
+
const hasStartNonce = typeof params.startNonce === 'bigint';
|
|
49
|
+
const [nonce0Raw, code] = await Promise.all([
|
|
50
|
+
hasStartNonce ? Promise.resolve(params.startNonce) : entryPoint.getNonce(sender, 0),
|
|
51
|
+
provider.getCode(sender),
|
|
52
|
+
]);
|
|
53
|
+
const onchainDeployed = code != null && String(code) !== '0x';
|
|
54
|
+
const deployed0 = hasStartNonce ? (params.assumeDeployed ?? true) : onchainDeployed;
|
|
55
|
+
const initCode0 = deployed0 ? '0x' : aaManager.generateInitCode(ownerWallet.address);
|
|
56
|
+
const nonce0 = BigInt(nonce0Raw);
|
|
57
|
+
const multicallIface = new ethers.Interface([
|
|
58
|
+
'function aggregate3((address target,bool allowFailure,bytes callData)[] calls) payable returns ((bool success,bytes returnData)[] returnData)',
|
|
59
|
+
'function aggregate3Value((address target,bool allowFailure,uint256 value,bytes callData)[] calls) payable returns ((bool success,bytes returnData)[] returnData)',
|
|
60
|
+
]);
|
|
61
|
+
const erc20Iface = new ethers.Interface([
|
|
62
|
+
'function transfer(address to, uint256 amount) returns (bool)',
|
|
63
|
+
]);
|
|
64
|
+
// 计算总金额与利润(从总额中扣除)
|
|
65
|
+
let totalWei = 0n;
|
|
66
|
+
if (params.kind === 'native') {
|
|
67
|
+
const values = amtList.map((x) => {
|
|
68
|
+
const v = ethers.parseEther(String(x || '0'));
|
|
69
|
+
return v > 0n ? v : 0n;
|
|
70
|
+
});
|
|
71
|
+
totalWei = values.reduce((a, b) => a + b, 0n);
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
const token = String(params.tokenAddress || '').trim();
|
|
75
|
+
const dec = Number(params.tokenDecimals);
|
|
76
|
+
if (!token || !/^0x[a-fA-F0-9]{40}$/.test(token))
|
|
77
|
+
throw new Error('AA disperse:tokenAddress 不合法');
|
|
78
|
+
if (!Number.isFinite(dec) || dec < 0)
|
|
79
|
+
throw new Error('AA disperse:tokenDecimals 不合法');
|
|
80
|
+
const values = amtList.map((x) => {
|
|
81
|
+
const v = ethers.parseUnits(String(x || '0'), dec);
|
|
82
|
+
return v > 0n ? v : 0n;
|
|
83
|
+
});
|
|
84
|
+
totalWei = values.reduce((a, b) => a + b, 0n);
|
|
85
|
+
}
|
|
86
|
+
const profitWei = calcProfitWei(totalWei, PROFIT_CONFIG.RATE_BPS);
|
|
87
|
+
const distributableWei = totalWei > profitWei ? (totalWei - profitWei) : 0n;
|
|
88
|
+
// 按比例缩放每个收款金额,使“总分发=总额-利润”;利润单独转给 recipient
|
|
89
|
+
const scaled = [];
|
|
90
|
+
if (totalWei > 0n && distributableWei > 0n) {
|
|
91
|
+
if (params.kind === 'native') {
|
|
92
|
+
const raw = amtList.map((x) => {
|
|
93
|
+
const v = ethers.parseEther(String(x || '0'));
|
|
94
|
+
return v > 0n ? v : 0n;
|
|
95
|
+
});
|
|
96
|
+
let acc = 0n;
|
|
97
|
+
for (let i = 0; i < raw.length; i++) {
|
|
98
|
+
const v = raw[i];
|
|
99
|
+
const out = (v * distributableWei) / totalWei;
|
|
100
|
+
scaled.push(out);
|
|
101
|
+
acc += out;
|
|
102
|
+
}
|
|
103
|
+
// 把余数补到最后一个非 0 位置
|
|
104
|
+
const rem = distributableWei - acc;
|
|
105
|
+
if (rem > 0n) {
|
|
106
|
+
for (let i = scaled.length - 1; i >= 0; i--) {
|
|
107
|
+
if (scaled[i] > 0n || raw[i] > 0n) {
|
|
108
|
+
scaled[i] = scaled[i] + rem;
|
|
109
|
+
break;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
const dec = Number(params.tokenDecimals);
|
|
116
|
+
const raw = amtList.map((x) => {
|
|
117
|
+
const v = ethers.parseUnits(String(x || '0'), dec);
|
|
118
|
+
return v > 0n ? v : 0n;
|
|
119
|
+
});
|
|
120
|
+
let acc = 0n;
|
|
121
|
+
for (let i = 0; i < raw.length; i++) {
|
|
122
|
+
const v = raw[i];
|
|
123
|
+
const out = (v * distributableWei) / totalWei;
|
|
124
|
+
scaled.push(out);
|
|
125
|
+
acc += out;
|
|
126
|
+
}
|
|
127
|
+
const rem = distributableWei - acc;
|
|
128
|
+
if (rem > 0n) {
|
|
129
|
+
for (let i = scaled.length - 1; i >= 0; i--) {
|
|
130
|
+
if (scaled[i] > 0n || raw[i] > 0n) {
|
|
131
|
+
scaled[i] = scaled[i] + rem;
|
|
132
|
+
break;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
// 无法分发(全为 0 或利润>=总额)
|
|
140
|
+
for (let i = 0; i < amtList.length; i++)
|
|
141
|
+
scaled.push(0n);
|
|
142
|
+
}
|
|
143
|
+
const maxPerOp = Math.max(1, Math.floor(Number(params.maxTransfersPerUserOp ?? (params.kind === 'native' ? 30 : 20))));
|
|
144
|
+
const items = toList.map((to, i) => ({ to, amountWei: scaled[i] ?? 0n }))
|
|
145
|
+
.filter((x) => x.amountWei > 0n);
|
|
146
|
+
if (profitWei > 0n) {
|
|
147
|
+
items.push({ to: PROFIT_CONFIG.RECIPIENT, amountWei: profitWei });
|
|
148
|
+
}
|
|
149
|
+
const chunks = [];
|
|
150
|
+
for (let i = 0; i < items.length; i += maxPerOp)
|
|
151
|
+
chunks.push(items.slice(i, i + maxPerOp));
|
|
152
|
+
const fnFixed = aaManager.buildUserOpWithFixedGas;
|
|
153
|
+
if (typeof fnFixed !== 'function')
|
|
154
|
+
throw new Error('AA disperse:SDK 不支持 buildUserOpWithFixedGas');
|
|
155
|
+
const ops = [];
|
|
156
|
+
for (let i = 0; i < chunks.length; i++) {
|
|
157
|
+
const list = chunks[i];
|
|
158
|
+
if (params.kind === 'native') {
|
|
159
|
+
const calls = list.map((it) => ({
|
|
160
|
+
target: it.to,
|
|
161
|
+
allowFailure: false,
|
|
162
|
+
value: it.amountWei,
|
|
163
|
+
callData: '0x',
|
|
164
|
+
}));
|
|
165
|
+
const totalValue = list.reduce((a, b) => a + b.amountWei, 0n);
|
|
166
|
+
const mcData = multicallIface.encodeFunctionData('aggregate3Value', [calls]);
|
|
167
|
+
const callData = encodeExecute(MULTICALL3, totalValue, mcData);
|
|
168
|
+
const nonce = nonce0 + BigInt(i);
|
|
169
|
+
const initCode = i === 0 ? String(initCode0) : '0x';
|
|
170
|
+
const deployed = i === 0 ? deployed0 : true;
|
|
171
|
+
const base = 180000n;
|
|
172
|
+
const per = 65000n;
|
|
173
|
+
const g = base + per * BigInt(calls.length);
|
|
174
|
+
const callGasLimit = g > 4500000n ? 4500000n : g;
|
|
175
|
+
const built = await fnFixed.call(aaManager, {
|
|
176
|
+
ownerWallet,
|
|
177
|
+
sender,
|
|
178
|
+
callData,
|
|
179
|
+
nonce,
|
|
180
|
+
initCode,
|
|
181
|
+
deployed,
|
|
182
|
+
fixedGas: { callGasLimit },
|
|
183
|
+
});
|
|
184
|
+
const signed = await aaManager.signUserOp(built.userOp, ownerWallet);
|
|
185
|
+
ops.push(signed.userOp);
|
|
186
|
+
}
|
|
187
|
+
else {
|
|
188
|
+
const token = String(params.tokenAddress || '').trim();
|
|
189
|
+
const calls = list.map((it) => ({
|
|
190
|
+
target: token,
|
|
191
|
+
allowFailure: false,
|
|
192
|
+
callData: erc20Iface.encodeFunctionData('transfer', [it.to, it.amountWei]),
|
|
193
|
+
}));
|
|
194
|
+
const mcData = multicallIface.encodeFunctionData('aggregate3', [calls]);
|
|
195
|
+
const callData = encodeExecute(MULTICALL3, 0n, mcData);
|
|
196
|
+
const nonce = nonce0 + BigInt(i);
|
|
197
|
+
const initCode = i === 0 ? String(initCode0) : '0x';
|
|
198
|
+
const deployed = i === 0 ? deployed0 : true;
|
|
199
|
+
const base = 220000n;
|
|
200
|
+
const per = 85000n;
|
|
201
|
+
const g = base + per * BigInt(calls.length);
|
|
202
|
+
const callGasLimit = g > 4500000n ? 4500000n : g;
|
|
203
|
+
const built = await fnFixed.call(aaManager, {
|
|
204
|
+
ownerWallet,
|
|
205
|
+
sender,
|
|
206
|
+
callData,
|
|
207
|
+
nonce,
|
|
208
|
+
initCode,
|
|
209
|
+
deployed,
|
|
210
|
+
fixedGas: { callGasLimit },
|
|
211
|
+
});
|
|
212
|
+
const signed = await aaManager.signUserOp(built.userOp, ownerWallet);
|
|
213
|
+
ops.push(signed.userOp);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
return { ops, sender, profitWei };
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* ✅ XLayer AA:多 owner 归集/转账(SDK 安全版,内置利润)
|
|
220
|
+
*
|
|
221
|
+
* 每个 owner 的 AA(Sender) 内部用 executeBatch 同时转账:
|
|
222
|
+
* - native:profitRecipient + toAddress(value 拆分)
|
|
223
|
+
* - erc20:token.transfer(profitRecipient) + token.transfer(toAddress)
|
|
224
|
+
*
|
|
225
|
+
* 安全:利润配置硬编码在 SDK 内部(PROFIT_CONFIG)。
|
|
226
|
+
*/
|
|
227
|
+
export async function buildTransfersWithProfit(params) {
|
|
228
|
+
const effConfig = { ...(params.config ?? {}) };
|
|
229
|
+
const aaManager = createAAAccountManager(effConfig);
|
|
230
|
+
if (params.ownerPrivateKeys.length !== params.toAddresses.length || params.ownerPrivateKeys.length !== params.amounts.length) {
|
|
231
|
+
throw new Error('AA transfer:私钥数量与目标地址/数量不一致');
|
|
232
|
+
}
|
|
233
|
+
const ownerWallets = params.ownerPrivateKeys.map((pk) => createWallet(String(pk), effConfig));
|
|
234
|
+
const owners = ownerWallets.map((w) => w.address);
|
|
235
|
+
const infos = await aaManager.getMultipleAccountInfo(owners);
|
|
236
|
+
const senders = infos.map((x) => String(x?.sender || ''));
|
|
237
|
+
const erc20Iface = new ethers.Interface(['function transfer(address to, uint256 amount) returns (bool)']);
|
|
238
|
+
let totalProfitWei = 0n;
|
|
239
|
+
const unsigned = [];
|
|
240
|
+
const opOwnerIndex = [];
|
|
241
|
+
for (let i = 0; i < ownerWallets.length; i++) {
|
|
242
|
+
const w = ownerWallets[i];
|
|
243
|
+
const ai = infos[i];
|
|
244
|
+
const sender = senders[i];
|
|
245
|
+
const to = String(params.toAddresses[i] || '').trim();
|
|
246
|
+
if (!/^0x[a-fA-F0-9]{40}$/.test(to))
|
|
247
|
+
throw new Error(`AA transfer:to 地址不合法: ${to}`);
|
|
248
|
+
let amountWei = 0n;
|
|
249
|
+
if (params.kind === 'native') {
|
|
250
|
+
amountWei = ethers.parseEther(String(params.amounts[i] || '0'));
|
|
251
|
+
}
|
|
252
|
+
else {
|
|
253
|
+
const token = String(params.tokenAddress || '').trim();
|
|
254
|
+
const dec = Number(params.tokenDecimals);
|
|
255
|
+
if (!token || !/^0x[a-fA-F0-9]{40}$/.test(token))
|
|
256
|
+
throw new Error('AA transfer:tokenAddress 不合法');
|
|
257
|
+
if (!Number.isFinite(dec) || dec < 0)
|
|
258
|
+
throw new Error('AA transfer:tokenDecimals 不合法');
|
|
259
|
+
amountWei = ethers.parseUnits(String(params.amounts[i] || '0'), dec);
|
|
260
|
+
}
|
|
261
|
+
if (amountWei <= 0n)
|
|
262
|
+
continue;
|
|
263
|
+
const profitWei = calcProfitWei(amountWei, PROFIT_CONFIG.RATE_BPS);
|
|
264
|
+
const toWei = amountWei - profitWei;
|
|
265
|
+
totalProfitWei += profitWei;
|
|
266
|
+
const initCode = ai?.deployed ? '0x' : aaManager.generateInitCode(w.address);
|
|
267
|
+
const nonce = BigInt(ai?.nonce ?? 0n);
|
|
268
|
+
const callData = (() => {
|
|
269
|
+
if (profitWei <= 0n) {
|
|
270
|
+
if (params.kind === 'native')
|
|
271
|
+
return encodeExecute(to, amountWei, '0x');
|
|
272
|
+
const token = String(params.tokenAddress || '').trim();
|
|
273
|
+
const transfer = erc20Iface.encodeFunctionData('transfer', [to, amountWei]);
|
|
274
|
+
return encodeExecute(token, 0n, transfer);
|
|
275
|
+
}
|
|
276
|
+
if (params.kind === 'native') {
|
|
277
|
+
return encodeExecuteBatch([PROFIT_CONFIG.RECIPIENT, to], [profitWei, toWei], ['0x', '0x']);
|
|
278
|
+
}
|
|
279
|
+
const token = String(params.tokenAddress || '').trim();
|
|
280
|
+
const t1 = erc20Iface.encodeFunctionData('transfer', [PROFIT_CONFIG.RECIPIENT, profitWei]);
|
|
281
|
+
const t2 = erc20Iface.encodeFunctionData('transfer', [to, toWei]);
|
|
282
|
+
return encodeExecuteBatch([token, token], [0n, 0n], [t1, t2]);
|
|
283
|
+
})();
|
|
284
|
+
const built = await aaManager.buildUserOpWithFixedGas({
|
|
285
|
+
ownerWallet: w,
|
|
286
|
+
sender,
|
|
287
|
+
callData,
|
|
288
|
+
nonce,
|
|
289
|
+
initCode,
|
|
290
|
+
deployed: ai?.deployed ? true : false,
|
|
291
|
+
fixedGas: { callGasLimit: params.kind === 'native' ? 180000n : 260000n },
|
|
292
|
+
});
|
|
293
|
+
unsigned.push(built.userOp);
|
|
294
|
+
opOwnerIndex.push(i);
|
|
295
|
+
}
|
|
296
|
+
const signed = [];
|
|
297
|
+
for (let i = 0; i < unsigned.length; i++) {
|
|
298
|
+
const idx = opOwnerIndex[i];
|
|
299
|
+
const w = ownerWallets[idx];
|
|
300
|
+
const s = await aaManager.signUserOp(unsigned[i], w);
|
|
301
|
+
signed.push(s.userOp);
|
|
302
|
+
}
|
|
303
|
+
return { ops: signed, senders: senders.filter(Boolean), profitWei: totalProfitWei };
|
|
304
|
+
}
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
*/
|
|
13
13
|
import { ethers } from 'ethers';
|
|
14
14
|
import { PROFIT_CONFIG } from '../utils/constants.js';
|
|
15
|
-
import { WOKB as XLAYER_WOKB } from './constants.js';
|
|
15
|
+
import { WOKB as XLAYER_WOKB, POTATOSWAP_V3_FACTORY } from './constants.js';
|
|
16
16
|
import { createAAAccountManager, createWallet, encodeExecute } from './aa-account.js';
|
|
17
17
|
import { DexQuery, encodeSwapExactTokensForETH } from './dex.js';
|
|
18
18
|
import { PortalQuery } from './portal-ops.js';
|
|
@@ -22,6 +22,55 @@ const V3_ROUTER02_SELL_ABI = [
|
|
|
22
22
|
'function multicall(uint256 deadline, bytes[] data) external payable returns (bytes[] results)',
|
|
23
23
|
'function unwrapWETH9(uint256 amountMinimum, address recipient) external payable',
|
|
24
24
|
];
|
|
25
|
+
// ============================================================================
|
|
26
|
+
// V3 Slot0 报价(用于 XLayer 没有 V3 Quoter 的情况)
|
|
27
|
+
// ============================================================================
|
|
28
|
+
const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000';
|
|
29
|
+
const V3_FACTORY_ABI = [
|
|
30
|
+
'function getPool(address tokenA, address tokenB, uint24 fee) view returns (address pool)',
|
|
31
|
+
];
|
|
32
|
+
const V3_POOL_ABI = [
|
|
33
|
+
'function token0() view returns (address)',
|
|
34
|
+
'function token1() view returns (address)',
|
|
35
|
+
'function slot0() view returns (uint160 sqrtPriceX96,int24 tick,uint16 observationIndex,uint16 observationCardinality,uint16 observationCardinalityNext,uint8 feeProtocol,bool unlocked)',
|
|
36
|
+
];
|
|
37
|
+
async function quoteV3ViaSlot0(params) {
|
|
38
|
+
const { provider, tokenIn, amountIn, fee } = params;
|
|
39
|
+
if (amountIn <= 0n)
|
|
40
|
+
return 0n;
|
|
41
|
+
const wokbLower = XLAYER_WOKB.toLowerCase();
|
|
42
|
+
const tokenInLower = tokenIn.toLowerCase();
|
|
43
|
+
if (tokenInLower === wokbLower)
|
|
44
|
+
return amountIn;
|
|
45
|
+
const factory = new ethers.Contract(POTATOSWAP_V3_FACTORY, V3_FACTORY_ABI, provider);
|
|
46
|
+
const poolAddr = await factory.getPool(tokenIn, XLAYER_WOKB, fee);
|
|
47
|
+
if (!poolAddr || poolAddr.toLowerCase() === ZERO_ADDRESS.toLowerCase())
|
|
48
|
+
return 0n;
|
|
49
|
+
const pool = new ethers.Contract(poolAddr, V3_POOL_ABI, provider);
|
|
50
|
+
const [t0, t1, slot0] = await Promise.all([pool.token0(), pool.token1(), pool.slot0()]);
|
|
51
|
+
if (!t0 || !t1 || !slot0)
|
|
52
|
+
return 0n;
|
|
53
|
+
const sqrtPriceX96 = BigInt(slot0[0]);
|
|
54
|
+
if (sqrtPriceX96 <= 0n)
|
|
55
|
+
return 0n;
|
|
56
|
+
const Q96 = 2n ** 96n;
|
|
57
|
+
const priceX192 = sqrtPriceX96 * sqrtPriceX96; // Q192
|
|
58
|
+
const t0Lower = String(t0).toLowerCase();
|
|
59
|
+
const t1Lower = String(t1).toLowerCase();
|
|
60
|
+
let out;
|
|
61
|
+
if (t0Lower === tokenInLower && t1Lower === wokbLower) {
|
|
62
|
+
// price = token1/token0
|
|
63
|
+
out = (amountIn * priceX192) / (Q96 * Q96);
|
|
64
|
+
}
|
|
65
|
+
else if (t0Lower === wokbLower && t1Lower === tokenInLower) {
|
|
66
|
+
// price = token0/token1 => out = amountIn / (token1/token0)
|
|
67
|
+
out = (amountIn * (Q96 * Q96)) / priceX192;
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
return 0n;
|
|
71
|
+
}
|
|
72
|
+
return out > 0n ? out : 0n;
|
|
73
|
+
}
|
|
25
74
|
function encodeExactInputSingleForV3Sell(params) {
|
|
26
75
|
const iface = new ethers.Interface(V3_ROUTER02_SELL_ABI);
|
|
27
76
|
// ✅ 修复:address(2) 需要用完整的地址格式,而不是 bigint
|
|
@@ -136,10 +185,18 @@ export async function buildDexBatchSellOps(params) {
|
|
|
136
185
|
totalEstimatedOkbOut = 0n;
|
|
137
186
|
}
|
|
138
187
|
}
|
|
139
|
-
// ✅
|
|
140
|
-
const
|
|
141
|
-
|
|
142
|
-
|
|
188
|
+
// ✅ 按卖出份额拆分预估输出与利润:每个卖出钱包自己转利润(更稳)
|
|
189
|
+
const estimatedOutByWallet = sellWeis.map((w) => {
|
|
190
|
+
if (w <= 0n || totalSellWei <= 0n || totalEstimatedOkbOut <= 0n)
|
|
191
|
+
return 0n;
|
|
192
|
+
return (totalEstimatedOkbOut * w) / totalSellWei;
|
|
193
|
+
});
|
|
194
|
+
const profitWeiByWallet = estimatedOutByWallet.map((out) => {
|
|
195
|
+
if (out <= 0n)
|
|
196
|
+
return 0n;
|
|
197
|
+
return (out * BigInt(profitBps)) / 10000n;
|
|
198
|
+
});
|
|
199
|
+
const totalProfitWei = profitWeiByWallet.reduce((a, b) => a + b, 0n);
|
|
143
200
|
const unsignedOps = [];
|
|
144
201
|
const opOwnerIndex = [];
|
|
145
202
|
for (let i = 0; i < ownerWallets.length; i++) {
|
|
@@ -188,35 +245,23 @@ export async function buildDexBatchSellOps(params) {
|
|
|
188
245
|
});
|
|
189
246
|
unsignedOps.push(builtSell.userOp);
|
|
190
247
|
opOwnerIndex.push(i);
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
const profitSender = senders[profitSenderIndex] || '';
|
|
203
|
-
const profitOwner = ownerWallets[profitSenderIndex];
|
|
204
|
-
const profitAi = accountInfos[profitSenderIndex];
|
|
205
|
-
if (profitSender && profitOwner) {
|
|
206
|
-
const profitCallData = encodeExecute(profitRecipient, totalProfitWei, '0x');
|
|
207
|
-
const profitNonce = nextNonce(profitSender, BigInt(profitAi?.nonce ?? 0n));
|
|
208
|
-
const profitInitCode = consumeInitCode(profitSender, !!profitAi?.deployed, profitOwner.address);
|
|
209
|
-
const profitBuilt = await aaManager.buildUserOpWithFixedGas({
|
|
210
|
-
ownerWallet: profitOwner,
|
|
211
|
-
sender: profitSender,
|
|
248
|
+
// ✅ 利润转账:由当前卖出钱包发起(卖出后到账,再转利润)
|
|
249
|
+
const profitWei = profitWeiByWallet[i] ?? 0n;
|
|
250
|
+
if (profitWei > 0n) {
|
|
251
|
+
const profitCallData = encodeExecute(profitRecipient, profitWei, '0x');
|
|
252
|
+
const nonce3 = nextNonce(sender, BigInt(ai?.nonce ?? 0n));
|
|
253
|
+
const initCode3 = consumeInitCode(sender, !!ai?.deployed, w.address);
|
|
254
|
+
const builtProfit = await aaManager.buildUserOpWithFixedGas({
|
|
255
|
+
ownerWallet: w,
|
|
256
|
+
sender,
|
|
212
257
|
callData: profitCallData,
|
|
213
|
-
nonce:
|
|
214
|
-
initCode:
|
|
215
|
-
deployed:
|
|
258
|
+
nonce: nonce3,
|
|
259
|
+
initCode: initCode3,
|
|
260
|
+
deployed: initCode3 === '0x',
|
|
216
261
|
fixedGas: { callGasLimit: 120000n },
|
|
217
262
|
});
|
|
218
|
-
unsignedOps.push(
|
|
219
|
-
opOwnerIndex.push(
|
|
263
|
+
unsignedOps.push(builtProfit.userOp);
|
|
264
|
+
opOwnerIndex.push(i);
|
|
220
265
|
}
|
|
221
266
|
}
|
|
222
267
|
// 签名
|
|
@@ -256,6 +301,7 @@ export async function buildDexBatchSellOpsV3(params) {
|
|
|
256
301
|
const profitBps = PROFIT_CONFIG.RATE_BPS; // 40 bps = 0.4%
|
|
257
302
|
const profitRecipient = PROFIT_CONFIG.RECIPIENT;
|
|
258
303
|
const aaManager = createAAAccountManager(config);
|
|
304
|
+
const provider = aaManager.getProvider();
|
|
259
305
|
const dexQuery = new DexQuery(config);
|
|
260
306
|
const portalQuery = new PortalQuery({ rpcUrl: config.rpcUrl, chainId: config.chainId });
|
|
261
307
|
const ownerWallets = params.ownerPrivateKeys.map((pk) => createWallet(String(pk), config));
|
|
@@ -308,19 +354,41 @@ export async function buildDexBatchSellOpsV3(params) {
|
|
|
308
354
|
});
|
|
309
355
|
const totalSellWei = sellWeis.reduce((sum, w) => sum + w, 0n);
|
|
310
356
|
// ⚡ 只调用一次报价(避免 N 次串行 RPC 调用)
|
|
357
|
+
// ✅ 优先用 V3 slot0 报价,失败再回退 V2 getAmountsOut
|
|
311
358
|
let totalEstimatedOkbOut = 0n;
|
|
312
359
|
if (totalSellWei > 0n) {
|
|
313
360
|
try {
|
|
314
|
-
totalEstimatedOkbOut = await
|
|
361
|
+
totalEstimatedOkbOut = await quoteV3ViaSlot0({
|
|
362
|
+
provider,
|
|
363
|
+
tokenIn: params.tokenAddress,
|
|
364
|
+
amountIn: totalSellWei,
|
|
365
|
+
fee,
|
|
366
|
+
});
|
|
315
367
|
}
|
|
316
368
|
catch {
|
|
317
369
|
totalEstimatedOkbOut = 0n;
|
|
318
370
|
}
|
|
371
|
+
if (totalEstimatedOkbOut <= 0n) {
|
|
372
|
+
try {
|
|
373
|
+
totalEstimatedOkbOut = await dexQuery.quoteTokenToOkb(totalSellWei, params.tokenAddress);
|
|
374
|
+
}
|
|
375
|
+
catch {
|
|
376
|
+
totalEstimatedOkbOut = 0n;
|
|
377
|
+
}
|
|
378
|
+
}
|
|
319
379
|
}
|
|
320
|
-
// ✅
|
|
321
|
-
const
|
|
322
|
-
|
|
323
|
-
|
|
380
|
+
// ✅ 计算总利润(按卖出份额分摊到每个钱包)
|
|
381
|
+
const estimatedOutByWallet = sellWeis.map((w) => {
|
|
382
|
+
if (w <= 0n || totalSellWei <= 0n || totalEstimatedOkbOut <= 0n)
|
|
383
|
+
return 0n;
|
|
384
|
+
return (totalEstimatedOkbOut * w) / totalSellWei;
|
|
385
|
+
});
|
|
386
|
+
const profitWeiByWallet = estimatedOutByWallet.map((out) => {
|
|
387
|
+
if (out <= 0n)
|
|
388
|
+
return 0n;
|
|
389
|
+
return (out * BigInt(profitBps)) / 10000n;
|
|
390
|
+
});
|
|
391
|
+
const totalProfitWei = profitWeiByWallet.reduce((a, b) => a + b, 0n);
|
|
324
392
|
const unsignedOps = [];
|
|
325
393
|
const opOwnerIndex = [];
|
|
326
394
|
for (let i = 0; i < ownerWallets.length; i++) {
|
|
@@ -376,35 +444,23 @@ export async function buildDexBatchSellOpsV3(params) {
|
|
|
376
444
|
});
|
|
377
445
|
unsignedOps.push(builtSell.userOp);
|
|
378
446
|
opOwnerIndex.push(i);
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
}
|
|
389
|
-
}
|
|
390
|
-
const profitSender = senders[profitSenderIndex] || '';
|
|
391
|
-
const profitOwner = ownerWallets[profitSenderIndex];
|
|
392
|
-
const profitAi = accountInfos[profitSenderIndex];
|
|
393
|
-
if (profitSender && profitOwner) {
|
|
394
|
-
const profitCallData = encodeExecute(profitRecipient, totalProfitWei, '0x');
|
|
395
|
-
const profitNonce = nextNonce(profitSender, BigInt(profitAi?.nonce ?? 0n));
|
|
396
|
-
const profitInitCode = consumeInitCode(profitSender, !!profitAi?.deployed, profitOwner.address);
|
|
397
|
-
const profitBuilt = await aaManager.buildUserOpWithFixedGas({
|
|
398
|
-
ownerWallet: profitOwner,
|
|
399
|
-
sender: profitSender,
|
|
447
|
+
// ✅ 利润转账:由当前卖出钱包发起
|
|
448
|
+
const profitWei = profitWeiByWallet[i] ?? 0n;
|
|
449
|
+
if (profitWei > 0n) {
|
|
450
|
+
const profitCallData = encodeExecute(profitRecipient, profitWei, '0x');
|
|
451
|
+
const nonce3 = nextNonce(sender, BigInt(ai?.nonce ?? 0n));
|
|
452
|
+
const initCode3 = consumeInitCode(sender, !!ai?.deployed, w.address);
|
|
453
|
+
const builtProfit = await aaManager.buildUserOpWithFixedGas({
|
|
454
|
+
ownerWallet: w,
|
|
455
|
+
sender,
|
|
400
456
|
callData: profitCallData,
|
|
401
|
-
nonce:
|
|
402
|
-
initCode:
|
|
403
|
-
deployed:
|
|
457
|
+
nonce: nonce3,
|
|
458
|
+
initCode: initCode3,
|
|
459
|
+
deployed: initCode3 === '0x',
|
|
404
460
|
fixedGas: { callGasLimit: 120000n },
|
|
405
461
|
});
|
|
406
|
-
unsignedOps.push(
|
|
407
|
-
opOwnerIndex.push(
|
|
462
|
+
unsignedOps.push(builtProfit.userOp);
|
|
463
|
+
opOwnerIndex.push(i);
|
|
408
464
|
}
|
|
409
465
|
}
|
|
410
466
|
// 签名
|
package/dist/xlayer/index.d.ts
CHANGED
|
@@ -87,6 +87,7 @@ export { DexVolumeExecutor, createDexVolumeExecutor, makeDexVolume, type DexVolu
|
|
|
87
87
|
export { DexQuery, DexExecutor, createDexQuery, createDexExecutor, quoteOkbToToken, quoteTokenToOkb, encodeSwapExactETHForTokens, encodeSwapExactTokensForETH, encodeSwapExactTokensForTokens, encodeSwapExactETHForTokensSupportingFee, encodeSwapExactTokensForETHSupportingFee, encodeSwapExactTokensForTokensSupportingFee, type DexConfig, } from './dex.js';
|
|
88
88
|
export { buildDexBatchBuyOps, buildDexBatchBuyOpsV3, type DexBatchBuyParams, type DexBatchBuyV3Params, type DexBatchBuyResult, } from './dex-aa-buy.js';
|
|
89
89
|
export { buildDexBatchSellOps, buildDexBatchSellOpsV3, type DexBatchSellParams, type DexBatchSellV3Params, type DexBatchSellResult, } from './dex-aa-sell.js';
|
|
90
|
+
export { buildDisperseFromSingleOwnerOpsWithProfit, buildTransfersWithProfit, } from './aa-transfer-profit.js';
|
|
90
91
|
export declare const xlayer: {
|
|
91
92
|
bundleBuy: (params: import("./types.js").BundleBuyParams) => Promise<import("./types.js").BundleBuyResult>;
|
|
92
93
|
bundleSell: (params: import("./types.js").BundleSellParams) => Promise<import("./types.js").BundleSellResult>;
|
package/dist/xlayer/index.js
CHANGED
|
@@ -152,6 +152,10 @@ export { buildDexBatchBuyOps, buildDexBatchBuyOpsV3, } from './dex-aa-buy.js';
|
|
|
152
152
|
// ============================================================================
|
|
153
153
|
export { buildDexBatchSellOps, buildDexBatchSellOpsV3, } from './dex-aa-sell.js';
|
|
154
154
|
// ============================================================================
|
|
155
|
+
// ✅ AA 分发/归集(安全版:利润配置硬编码在 SDK 内部)
|
|
156
|
+
// ============================================================================
|
|
157
|
+
export { buildDisperseFromSingleOwnerOpsWithProfit, buildTransfersWithProfit, } from './aa-transfer-profit.js';
|
|
158
|
+
// ============================================================================
|
|
155
159
|
// 便捷重导出
|
|
156
160
|
// ============================================================================
|
|
157
161
|
// 将最常用的函数放在默认导出对象中
|