anchor-sdk 0.1.41-internal.5 → 0.1.42-beta.0
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/AnchorApiClientV2.d.ts +6 -1
- package/dist/AnchorPayClient.d.ts +54 -0
- package/dist/AnchorPayClient.js +414 -0
- package/dist/constants.d.ts +111 -0
- package/dist/constants.js +147 -1
- package/dist/generated/Api.d.ts +620 -555
- package/dist/generated/Api.js +15 -0
- package/package.json +83 -85
- package/dist/AnchorApiClient.d.ts +0 -203
- package/dist/AnchorApiClient.js +0 -279
- package/dist/api/AnchorApiHttpClient.d.ts +0 -210
- package/dist/api/AnchorApiHttpClient.js +0 -411
- package/dist/api/types.d.ts +0 -764
- package/dist/api/types.js +0 -2
|
@@ -128,6 +128,7 @@ export declare class AnchorApiClientV2 {
|
|
|
128
128
|
getBadgeSeriesDetail(seriesId: string, params?: {
|
|
129
129
|
status?: string;
|
|
130
130
|
businessType?: string;
|
|
131
|
+
tokenIds?: string[];
|
|
131
132
|
}): Promise<WebResultBadgeSeriesDetailResponse>;
|
|
132
133
|
/**
|
|
133
134
|
* 获取徽章详情
|
|
@@ -150,7 +151,11 @@ export declare class AnchorApiClientV2 {
|
|
|
150
151
|
* @param data 徽章检查请求
|
|
151
152
|
* @returns 徽章检查响应
|
|
152
153
|
*/
|
|
153
|
-
checkUserClaimableBadges(data:
|
|
154
|
+
checkUserClaimableBadges(data: {
|
|
155
|
+
walletType?: "ALL" | "EVM" | "SOLANA";
|
|
156
|
+
groups?: string[];
|
|
157
|
+
[key: string]: any;
|
|
158
|
+
}): Promise<WebResultBadgeCheckResponse>;
|
|
154
159
|
/**
|
|
155
160
|
* 获取徽章领取签名
|
|
156
161
|
* @route POST /v2/badges/signatures
|
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
import { Account, Address, Chain, Hex, PublicClient, TransactionReceipt, WalletClient } from "viem";
|
|
2
2
|
import { PaymentOptions } from "./types";
|
|
3
|
+
/**
|
|
4
|
+
* 批量转账参数
|
|
5
|
+
*/
|
|
6
|
+
export interface BatchTransferItem {
|
|
7
|
+
recipient: Address;
|
|
8
|
+
amount: bigint;
|
|
9
|
+
data?: Hex;
|
|
10
|
+
}
|
|
3
11
|
/**
|
|
4
12
|
* AnchorPay 客户端
|
|
5
13
|
* 用于与 AnchorPay 合约交互
|
|
@@ -116,4 +124,50 @@ export declare class AnchorPayClient {
|
|
|
116
124
|
* @returns 交易收据
|
|
117
125
|
*/
|
|
118
126
|
withdraw(tokenAddress: Address, amount: bigint, options?: PaymentOptions): Promise<TransactionReceipt>;
|
|
127
|
+
/**
|
|
128
|
+
* 批量存入 ETH(使用 Multicall3)
|
|
129
|
+
* @param deposits 批量存款参数数组,每项包含接收者地址和金额
|
|
130
|
+
* @param options 交易选项
|
|
131
|
+
* @returns 交易收据或交易数据
|
|
132
|
+
*/
|
|
133
|
+
batchDepositETH(deposits: BatchTransferItem[], options?: PaymentOptions): Promise<TransactionReceipt | {
|
|
134
|
+
to: string;
|
|
135
|
+
data: string;
|
|
136
|
+
value: bigint;
|
|
137
|
+
}>;
|
|
138
|
+
/**
|
|
139
|
+
* 批量存入 ERC20 代币(使用 Multicall3)
|
|
140
|
+
* @param tokenAddress ERC20 代币地址
|
|
141
|
+
* @param deposits 批量存款参数数组
|
|
142
|
+
* @param options 交易选项
|
|
143
|
+
* @returns 交易收据或交易数据
|
|
144
|
+
*/
|
|
145
|
+
batchDepositERC20(tokenAddress: Address, deposits: BatchTransferItem[], options?: PaymentOptions): Promise<TransactionReceipt | {
|
|
146
|
+
to: string;
|
|
147
|
+
data: string;
|
|
148
|
+
value: bigint;
|
|
149
|
+
}>;
|
|
150
|
+
/**
|
|
151
|
+
* 批量发送 ETH(使用 Multicall3)
|
|
152
|
+
* @param transfers 批量转账参数数组
|
|
153
|
+
* @param options 交易选项
|
|
154
|
+
* @returns 交易收据或交易数据
|
|
155
|
+
*/
|
|
156
|
+
batchSendETH(transfers: BatchTransferItem[], options?: PaymentOptions): Promise<TransactionReceipt | {
|
|
157
|
+
to: string;
|
|
158
|
+
data: string;
|
|
159
|
+
value: bigint;
|
|
160
|
+
}>;
|
|
161
|
+
/**
|
|
162
|
+
* 批量发送 ERC20 代币(使用 Multicall3)
|
|
163
|
+
* @param tokenAddress ERC20 代币地址
|
|
164
|
+
* @param transfers 批量转账参数数组
|
|
165
|
+
* @param options 交易选项
|
|
166
|
+
* @returns 交易收据或交易数据
|
|
167
|
+
*/
|
|
168
|
+
batchSendERC20(tokenAddress: Address, transfers: BatchTransferItem[], options?: PaymentOptions): Promise<TransactionReceipt | {
|
|
169
|
+
to: string;
|
|
170
|
+
data: string;
|
|
171
|
+
value: bigint;
|
|
172
|
+
}>;
|
|
119
173
|
}
|
package/dist/AnchorPayClient.js
CHANGED
|
@@ -490,5 +490,419 @@ class AnchorPayClient {
|
|
|
490
490
|
});
|
|
491
491
|
return receipt;
|
|
492
492
|
}
|
|
493
|
+
/**
|
|
494
|
+
* 批量存入 ETH(使用 Multicall3)
|
|
495
|
+
* @param deposits 批量存款参数数组,每项包含接收者地址和金额
|
|
496
|
+
* @param options 交易选项
|
|
497
|
+
* @returns 交易收据或交易数据
|
|
498
|
+
*/
|
|
499
|
+
async batchDepositETH(deposits, options) {
|
|
500
|
+
if (deposits.length === 0) {
|
|
501
|
+
throw new Error("No deposits provided");
|
|
502
|
+
}
|
|
503
|
+
// 如果需要发送交易,但没有钱包客户端或账户
|
|
504
|
+
if (options?.sendTransaction !== false &&
|
|
505
|
+
(!this.walletClient || !this.account)) {
|
|
506
|
+
throw new Error("Wallet client and account are required to send transactions");
|
|
507
|
+
}
|
|
508
|
+
// 准备批量调用数据
|
|
509
|
+
const calls = deposits.map((deposit) => {
|
|
510
|
+
const calldata = (0, viem_1.encodeFunctionData)({
|
|
511
|
+
abi: AnchorPay_json_1.default,
|
|
512
|
+
functionName: "depositFor",
|
|
513
|
+
args: [deposit.recipient, constants_1.NATIVE_TOKEN_ADDRESS, deposit.amount],
|
|
514
|
+
});
|
|
515
|
+
return {
|
|
516
|
+
target: this.contracts?.anchorPay || "",
|
|
517
|
+
allowFailure: false,
|
|
518
|
+
value: deposit.amount,
|
|
519
|
+
callData: calldata,
|
|
520
|
+
};
|
|
521
|
+
});
|
|
522
|
+
// 计算总金额
|
|
523
|
+
const totalValue = deposits.reduce((sum, deposit) => sum + deposit.amount, 0n);
|
|
524
|
+
// 编码 Multicall3 调用
|
|
525
|
+
const multicallData = (0, viem_1.encodeFunctionData)({
|
|
526
|
+
abi: constants_1.MULTICALL3_ABI,
|
|
527
|
+
functionName: "aggregate3Value",
|
|
528
|
+
args: [calls],
|
|
529
|
+
});
|
|
530
|
+
// 如果不需要发送交易,只返回交易数据(AA 模式)
|
|
531
|
+
if (options?.sendTransaction === false) {
|
|
532
|
+
return {
|
|
533
|
+
to: constants_1.MULTICALL3_ADDRESS,
|
|
534
|
+
data: multicallData,
|
|
535
|
+
value: totalValue,
|
|
536
|
+
};
|
|
537
|
+
}
|
|
538
|
+
// 估算 gas 和费用
|
|
539
|
+
const { maxFeePerGas, maxPriorityFeePerGas } = await this.publicClient.estimateFeesPerGas();
|
|
540
|
+
const gas = await this.publicClient.estimateGas({
|
|
541
|
+
to: constants_1.MULTICALL3_ADDRESS,
|
|
542
|
+
data: multicallData,
|
|
543
|
+
value: totalValue,
|
|
544
|
+
account: this.account,
|
|
545
|
+
});
|
|
546
|
+
// 发送交易(EOA 模式)
|
|
547
|
+
if (!this.walletClient || !this.account) {
|
|
548
|
+
throw new Error("Wallet client and account are required to send transactions");
|
|
549
|
+
}
|
|
550
|
+
const txHash = await this.walletClient.sendTransaction({
|
|
551
|
+
account: this.account,
|
|
552
|
+
to: constants_1.MULTICALL3_ADDRESS,
|
|
553
|
+
data: multicallData,
|
|
554
|
+
value: totalValue,
|
|
555
|
+
maxFeePerGas: options?.maxFeePerGas || maxFeePerGas,
|
|
556
|
+
maxPriorityFeePerGas: options?.maxPriorityFeePerGas || maxPriorityFeePerGas,
|
|
557
|
+
gas: options?.gas || gas,
|
|
558
|
+
chain: this.publicClient.chain,
|
|
559
|
+
});
|
|
560
|
+
// 等待交易确认并返回收据
|
|
561
|
+
const receipt = await this.publicClient.waitForTransactionReceipt({
|
|
562
|
+
hash: txHash,
|
|
563
|
+
});
|
|
564
|
+
return receipt;
|
|
565
|
+
}
|
|
566
|
+
/**
|
|
567
|
+
* 批量存入 ERC20 代币(使用 Multicall3)
|
|
568
|
+
* @param tokenAddress ERC20 代币地址
|
|
569
|
+
* @param deposits 批量存款参数数组
|
|
570
|
+
* @param options 交易选项
|
|
571
|
+
* @returns 交易收据或交易数据
|
|
572
|
+
*/
|
|
573
|
+
async batchDepositERC20(tokenAddress, deposits, options) {
|
|
574
|
+
if (deposits.length === 0) {
|
|
575
|
+
throw new Error("No deposits provided");
|
|
576
|
+
}
|
|
577
|
+
// 如果需要发送交易,但没有钱包客户端或账户
|
|
578
|
+
if (options?.sendTransaction !== false &&
|
|
579
|
+
(!this.walletClient || !this.account)) {
|
|
580
|
+
throw new Error("Wallet client and account are required to send transactions");
|
|
581
|
+
}
|
|
582
|
+
// 计算总金额(用于批准检查)
|
|
583
|
+
const totalAmount = deposits.reduce((sum, deposit) => sum + deposit.amount, 0n);
|
|
584
|
+
// 如果需要自动批准,则先批准代币(默认开启自动批准)
|
|
585
|
+
if (options?.autoApprove !== false && this.walletClient && this.account) {
|
|
586
|
+
try {
|
|
587
|
+
console.log(`Checking ERC20 token approval status: ${tokenAddress}`);
|
|
588
|
+
// 检查授权
|
|
589
|
+
const allowance = (await this.publicClient.readContract({
|
|
590
|
+
address: tokenAddress,
|
|
591
|
+
abi: constants_1.ERC20_ABI,
|
|
592
|
+
functionName: "allowance",
|
|
593
|
+
args: [this.account.address, this.contracts?.anchorPay],
|
|
594
|
+
}));
|
|
595
|
+
console.log(`Current allowance: ${allowance}, Required amount: ${totalAmount}, AnchorPay contract address: ${this.contracts?.anchorPay}`);
|
|
596
|
+
if (allowance < totalAmount) {
|
|
597
|
+
console.log(`Approving ${totalAmount} tokens to AnchorPay contract...`);
|
|
598
|
+
// 批准代币 - 使用最大可能值进行授权,避免多次授权
|
|
599
|
+
const maxApproveAmount = 2n ** 256n - 1n;
|
|
600
|
+
// 估算 gas 和费用
|
|
601
|
+
const { maxFeePerGas: approveMaxFeePerGas, maxPriorityFeePerGas: approveMaxPriorityFeePerGas, } = await this.publicClient.estimateFeesPerGas();
|
|
602
|
+
const approveCalldata = (0, viem_1.encodeFunctionData)({
|
|
603
|
+
abi: constants_1.ERC20_ABI,
|
|
604
|
+
functionName: "approve",
|
|
605
|
+
args: [this.contracts?.anchorPay, maxApproveAmount],
|
|
606
|
+
});
|
|
607
|
+
const approveGas = await this.publicClient.estimateGas({
|
|
608
|
+
to: tokenAddress,
|
|
609
|
+
data: approveCalldata,
|
|
610
|
+
value: 0n,
|
|
611
|
+
account: this.account,
|
|
612
|
+
});
|
|
613
|
+
const approveTxHash = await this.walletClient.writeContract({
|
|
614
|
+
account: this.account,
|
|
615
|
+
address: tokenAddress,
|
|
616
|
+
abi: constants_1.ERC20_ABI,
|
|
617
|
+
functionName: "approve",
|
|
618
|
+
args: [this.contracts?.anchorPay, maxApproveAmount],
|
|
619
|
+
chain: this.publicClient.chain,
|
|
620
|
+
maxFeePerGas: approveMaxFeePerGas,
|
|
621
|
+
maxPriorityFeePerGas: approveMaxPriorityFeePerGas,
|
|
622
|
+
gas: approveGas,
|
|
623
|
+
});
|
|
624
|
+
console.log(`Approval transaction sent, hash: ${approveTxHash}`);
|
|
625
|
+
// 等待交易确认
|
|
626
|
+
await this.publicClient.waitForTransactionReceipt({
|
|
627
|
+
hash: approveTxHash,
|
|
628
|
+
});
|
|
629
|
+
console.log(`Approval transaction confirmed`);
|
|
630
|
+
}
|
|
631
|
+
else {
|
|
632
|
+
console.log(`Sufficient allowance already exists, no need for additional approval`);
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
catch (error) {
|
|
636
|
+
console.error(`Approval failed:`, error);
|
|
637
|
+
throw new Error(`ERC20 approval failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
// 准备批量调用数据
|
|
641
|
+
const calls = deposits.map((deposit) => {
|
|
642
|
+
const calldata = (0, viem_1.encodeFunctionData)({
|
|
643
|
+
abi: AnchorPay_json_1.default,
|
|
644
|
+
functionName: "depositFor",
|
|
645
|
+
args: [deposit.recipient, tokenAddress, deposit.amount],
|
|
646
|
+
});
|
|
647
|
+
return {
|
|
648
|
+
target: this.contracts?.anchorPay || "",
|
|
649
|
+
allowFailure: false,
|
|
650
|
+
value: 0n,
|
|
651
|
+
callData: calldata,
|
|
652
|
+
};
|
|
653
|
+
});
|
|
654
|
+
// 编码 Multicall3 调用
|
|
655
|
+
const multicallData = (0, viem_1.encodeFunctionData)({
|
|
656
|
+
abi: constants_1.MULTICALL3_ABI,
|
|
657
|
+
functionName: "aggregate3Value",
|
|
658
|
+
args: [calls],
|
|
659
|
+
});
|
|
660
|
+
// 如果不需要发送交易,只返回交易数据(AA 模式)
|
|
661
|
+
if (options?.sendTransaction === false) {
|
|
662
|
+
return {
|
|
663
|
+
to: constants_1.MULTICALL3_ADDRESS,
|
|
664
|
+
data: multicallData,
|
|
665
|
+
value: 0n,
|
|
666
|
+
};
|
|
667
|
+
}
|
|
668
|
+
// 估算 gas 和费用
|
|
669
|
+
const { maxFeePerGas, maxPriorityFeePerGas } = await this.publicClient.estimateFeesPerGas();
|
|
670
|
+
const gas = await this.publicClient.estimateGas({
|
|
671
|
+
to: constants_1.MULTICALL3_ADDRESS,
|
|
672
|
+
data: multicallData,
|
|
673
|
+
value: 0n,
|
|
674
|
+
account: this.account,
|
|
675
|
+
});
|
|
676
|
+
// 发送交易(EOA 模式)
|
|
677
|
+
if (!this.walletClient || !this.account) {
|
|
678
|
+
throw new Error("Wallet client and account are required to send transactions");
|
|
679
|
+
}
|
|
680
|
+
const txHash = await this.walletClient.sendTransaction({
|
|
681
|
+
account: this.account,
|
|
682
|
+
to: constants_1.MULTICALL3_ADDRESS,
|
|
683
|
+
data: multicallData,
|
|
684
|
+
maxFeePerGas: options?.maxFeePerGas || maxFeePerGas,
|
|
685
|
+
maxPriorityFeePerGas: options?.maxPriorityFeePerGas || maxPriorityFeePerGas,
|
|
686
|
+
gas: options?.gas || gas,
|
|
687
|
+
chain: this.publicClient.chain,
|
|
688
|
+
});
|
|
689
|
+
// 等待交易确认并返回收据
|
|
690
|
+
const receipt = await this.publicClient.waitForTransactionReceipt({
|
|
691
|
+
hash: txHash,
|
|
692
|
+
});
|
|
693
|
+
return receipt;
|
|
694
|
+
}
|
|
695
|
+
/**
|
|
696
|
+
* 批量发送 ETH(使用 Multicall3)
|
|
697
|
+
* @param transfers 批量转账参数数组
|
|
698
|
+
* @param options 交易选项
|
|
699
|
+
* @returns 交易收据或交易数据
|
|
700
|
+
*/
|
|
701
|
+
async batchSendETH(transfers, options) {
|
|
702
|
+
if (transfers.length === 0) {
|
|
703
|
+
throw new Error("No transfers provided");
|
|
704
|
+
}
|
|
705
|
+
// 如果需要发送交易,但没有钱包客户端或账户
|
|
706
|
+
if (options?.sendTransaction !== false &&
|
|
707
|
+
(!this.walletClient || !this.account)) {
|
|
708
|
+
throw new Error("Wallet client and account are required to send transactions");
|
|
709
|
+
}
|
|
710
|
+
// 准备批量调用数据
|
|
711
|
+
const calls = transfers.map((transfer) => {
|
|
712
|
+
const calldata = (0, viem_1.encodeFunctionData)({
|
|
713
|
+
abi: AnchorPay_json_1.default,
|
|
714
|
+
functionName: "send",
|
|
715
|
+
args: [
|
|
716
|
+
transfer.recipient,
|
|
717
|
+
constants_1.NATIVE_TOKEN_ADDRESS,
|
|
718
|
+
transfer.amount,
|
|
719
|
+
transfer.data || "0x",
|
|
720
|
+
],
|
|
721
|
+
});
|
|
722
|
+
return {
|
|
723
|
+
target: this.contracts?.anchorPay || "",
|
|
724
|
+
allowFailure: false,
|
|
725
|
+
value: transfer.amount,
|
|
726
|
+
callData: calldata,
|
|
727
|
+
};
|
|
728
|
+
});
|
|
729
|
+
// 计算总金额
|
|
730
|
+
const totalValue = transfers.reduce((sum, transfer) => sum + transfer.amount, 0n);
|
|
731
|
+
// 编码 Multicall3 调用
|
|
732
|
+
const multicallData = (0, viem_1.encodeFunctionData)({
|
|
733
|
+
abi: constants_1.MULTICALL3_ABI,
|
|
734
|
+
functionName: "aggregate3Value",
|
|
735
|
+
args: [calls],
|
|
736
|
+
});
|
|
737
|
+
// 如果不需要发送交易,只返回交易数据(AA 模式)
|
|
738
|
+
if (options?.sendTransaction === false) {
|
|
739
|
+
return {
|
|
740
|
+
to: constants_1.MULTICALL3_ADDRESS,
|
|
741
|
+
data: multicallData,
|
|
742
|
+
value: totalValue,
|
|
743
|
+
};
|
|
744
|
+
}
|
|
745
|
+
// 估算 gas 和费用
|
|
746
|
+
const { maxFeePerGas, maxPriorityFeePerGas } = await this.publicClient.estimateFeesPerGas();
|
|
747
|
+
const gas = await this.publicClient.estimateGas({
|
|
748
|
+
to: constants_1.MULTICALL3_ADDRESS,
|
|
749
|
+
data: multicallData,
|
|
750
|
+
value: totalValue,
|
|
751
|
+
account: this.account,
|
|
752
|
+
});
|
|
753
|
+
// 发送交易(EOA 模式)
|
|
754
|
+
if (!this.walletClient || !this.account) {
|
|
755
|
+
throw new Error("Wallet client and account are required to send transactions");
|
|
756
|
+
}
|
|
757
|
+
const txHash = await this.walletClient.sendTransaction({
|
|
758
|
+
account: this.account,
|
|
759
|
+
to: constants_1.MULTICALL3_ADDRESS,
|
|
760
|
+
data: multicallData,
|
|
761
|
+
value: totalValue,
|
|
762
|
+
maxFeePerGas: options?.maxFeePerGas || maxFeePerGas,
|
|
763
|
+
maxPriorityFeePerGas: options?.maxPriorityFeePerGas || maxPriorityFeePerGas,
|
|
764
|
+
gas: options?.gas || gas,
|
|
765
|
+
chain: this.publicClient.chain,
|
|
766
|
+
});
|
|
767
|
+
// 等待交易确认并返回收据
|
|
768
|
+
const receipt = await this.publicClient.waitForTransactionReceipt({
|
|
769
|
+
hash: txHash,
|
|
770
|
+
});
|
|
771
|
+
return receipt;
|
|
772
|
+
}
|
|
773
|
+
/**
|
|
774
|
+
* 批量发送 ERC20 代币(使用 Multicall3)
|
|
775
|
+
* @param tokenAddress ERC20 代币地址
|
|
776
|
+
* @param transfers 批量转账参数数组
|
|
777
|
+
* @param options 交易选项
|
|
778
|
+
* @returns 交易收据或交易数据
|
|
779
|
+
*/
|
|
780
|
+
async batchSendERC20(tokenAddress, transfers, options) {
|
|
781
|
+
if (transfers.length === 0) {
|
|
782
|
+
throw new Error("No transfers provided");
|
|
783
|
+
}
|
|
784
|
+
// 如果需要发送交易,但没有钱包客户端或账户
|
|
785
|
+
if (options?.sendTransaction !== false &&
|
|
786
|
+
(!this.walletClient || !this.account)) {
|
|
787
|
+
throw new Error("Wallet client and account are required to send transactions");
|
|
788
|
+
}
|
|
789
|
+
// 计算总金额(用于批准检查)
|
|
790
|
+
const totalAmount = transfers.reduce((sum, transfer) => sum + transfer.amount, 0n);
|
|
791
|
+
// 如果需要自动批准,则先批准代币(默认开启自动批准)
|
|
792
|
+
if (options?.autoApprove !== false && this.walletClient && this.account) {
|
|
793
|
+
try {
|
|
794
|
+
console.log(`Checking ERC20 token approval status: ${tokenAddress}`);
|
|
795
|
+
// 检查授权
|
|
796
|
+
const allowance = (await this.publicClient.readContract({
|
|
797
|
+
address: tokenAddress,
|
|
798
|
+
abi: constants_1.ERC20_ABI,
|
|
799
|
+
functionName: "allowance",
|
|
800
|
+
args: [this.account.address, this.contracts?.anchorPay],
|
|
801
|
+
}));
|
|
802
|
+
console.log(`Current allowance: ${allowance}, Required amount: ${totalAmount}, AnchorPay contract address: ${this.contracts?.anchorPay}`);
|
|
803
|
+
if (allowance < totalAmount) {
|
|
804
|
+
console.log(`Approving ${totalAmount} tokens to AnchorPay contract...`);
|
|
805
|
+
// 批准代币 - 使用最大可能值进行授权,避免多次授权
|
|
806
|
+
const maxApproveAmount = 2n ** 256n - 1n;
|
|
807
|
+
// 估算 gas 和费用
|
|
808
|
+
const { maxFeePerGas: approveMaxFeePerGas, maxPriorityFeePerGas: approveMaxPriorityFeePerGas, } = await this.publicClient.estimateFeesPerGas();
|
|
809
|
+
const approveCalldata = (0, viem_1.encodeFunctionData)({
|
|
810
|
+
abi: constants_1.ERC20_ABI,
|
|
811
|
+
functionName: "approve",
|
|
812
|
+
args: [this.contracts?.anchorPay, maxApproveAmount],
|
|
813
|
+
});
|
|
814
|
+
const approveGas = await this.publicClient.estimateGas({
|
|
815
|
+
to: tokenAddress,
|
|
816
|
+
data: approveCalldata,
|
|
817
|
+
value: 0n,
|
|
818
|
+
account: this.account,
|
|
819
|
+
});
|
|
820
|
+
const approveTxHash = await this.walletClient.writeContract({
|
|
821
|
+
account: this.account,
|
|
822
|
+
address: tokenAddress,
|
|
823
|
+
abi: constants_1.ERC20_ABI,
|
|
824
|
+
functionName: "approve",
|
|
825
|
+
args: [this.contracts?.anchorPay, maxApproveAmount],
|
|
826
|
+
chain: this.publicClient.chain,
|
|
827
|
+
maxFeePerGas: approveMaxFeePerGas,
|
|
828
|
+
maxPriorityFeePerGas: approveMaxPriorityFeePerGas,
|
|
829
|
+
gas: approveGas,
|
|
830
|
+
});
|
|
831
|
+
console.log(`Approval transaction sent, hash: ${approveTxHash}`);
|
|
832
|
+
// 等待交易确认
|
|
833
|
+
await this.publicClient.waitForTransactionReceipt({
|
|
834
|
+
hash: approveTxHash,
|
|
835
|
+
});
|
|
836
|
+
console.log(`Approval transaction confirmed`);
|
|
837
|
+
}
|
|
838
|
+
else {
|
|
839
|
+
console.log(`Sufficient allowance already exists, no need for additional approval`);
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
catch (error) {
|
|
843
|
+
console.error(`Approval failed:`, error);
|
|
844
|
+
throw new Error(`ERC20 approval failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
// 准备批量调用数据
|
|
848
|
+
const calls = transfers.map((transfer) => {
|
|
849
|
+
const calldata = (0, viem_1.encodeFunctionData)({
|
|
850
|
+
abi: AnchorPay_json_1.default,
|
|
851
|
+
functionName: "send",
|
|
852
|
+
args: [
|
|
853
|
+
transfer.recipient,
|
|
854
|
+
tokenAddress,
|
|
855
|
+
transfer.amount,
|
|
856
|
+
transfer.data || "0x",
|
|
857
|
+
],
|
|
858
|
+
});
|
|
859
|
+
return {
|
|
860
|
+
target: this.contracts?.anchorPay || "",
|
|
861
|
+
allowFailure: false,
|
|
862
|
+
value: 0n,
|
|
863
|
+
callData: calldata,
|
|
864
|
+
};
|
|
865
|
+
});
|
|
866
|
+
// 编码 Multicall3 调用
|
|
867
|
+
const multicallData = (0, viem_1.encodeFunctionData)({
|
|
868
|
+
abi: constants_1.MULTICALL3_ABI,
|
|
869
|
+
functionName: "aggregate3Value",
|
|
870
|
+
args: [calls],
|
|
871
|
+
});
|
|
872
|
+
// 如果不需要发送交易,只返回交易数据(AA 模式)
|
|
873
|
+
if (options?.sendTransaction === false) {
|
|
874
|
+
return {
|
|
875
|
+
to: constants_1.MULTICALL3_ADDRESS,
|
|
876
|
+
data: multicallData,
|
|
877
|
+
value: 0n,
|
|
878
|
+
};
|
|
879
|
+
}
|
|
880
|
+
// 估算 gas 和费用
|
|
881
|
+
const { maxFeePerGas, maxPriorityFeePerGas } = await this.publicClient.estimateFeesPerGas();
|
|
882
|
+
const gas = await this.publicClient.estimateGas({
|
|
883
|
+
to: constants_1.MULTICALL3_ADDRESS,
|
|
884
|
+
data: multicallData,
|
|
885
|
+
value: 0n,
|
|
886
|
+
account: this.account,
|
|
887
|
+
});
|
|
888
|
+
// 发送交易(EOA 模式)
|
|
889
|
+
if (!this.walletClient || !this.account) {
|
|
890
|
+
throw new Error("Wallet client and account are required to send transactions");
|
|
891
|
+
}
|
|
892
|
+
const txHash = await this.walletClient.sendTransaction({
|
|
893
|
+
account: this.account,
|
|
894
|
+
to: constants_1.MULTICALL3_ADDRESS,
|
|
895
|
+
data: multicallData,
|
|
896
|
+
maxFeePerGas: options?.maxFeePerGas || maxFeePerGas,
|
|
897
|
+
maxPriorityFeePerGas: options?.maxPriorityFeePerGas || maxPriorityFeePerGas,
|
|
898
|
+
gas: options?.gas || gas,
|
|
899
|
+
chain: this.publicClient.chain,
|
|
900
|
+
});
|
|
901
|
+
// 等待交易确认并返回收据
|
|
902
|
+
const receipt = await this.publicClient.waitForTransactionReceipt({
|
|
903
|
+
hash: txHash,
|
|
904
|
+
});
|
|
905
|
+
return receipt;
|
|
906
|
+
}
|
|
493
907
|
}
|
|
494
908
|
exports.AnchorPayClient = AnchorPayClient;
|
package/dist/constants.d.ts
CHANGED
|
@@ -47,3 +47,114 @@ export declare const INTERFACE_HASHES: {
|
|
|
47
47
|
TOKEN_RECEIVED: string;
|
|
48
48
|
};
|
|
49
49
|
export declare const NATIVE_TOKEN_ADDRESS = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE";
|
|
50
|
+
/**
|
|
51
|
+
* Multicall3 合约地址(跨链通用)
|
|
52
|
+
*/
|
|
53
|
+
export declare const MULTICALL3_ADDRESS = "0xcA11bde05977b3631167028862bE2a173976CA11";
|
|
54
|
+
/**
|
|
55
|
+
* Multicall3 合约 ABI
|
|
56
|
+
*/
|
|
57
|
+
export declare const MULTICALL3_ABI: readonly [{
|
|
58
|
+
readonly inputs: readonly [{
|
|
59
|
+
readonly components: readonly [{
|
|
60
|
+
readonly internalType: "address";
|
|
61
|
+
readonly name: "target";
|
|
62
|
+
readonly type: "address";
|
|
63
|
+
}, {
|
|
64
|
+
readonly internalType: "bytes";
|
|
65
|
+
readonly name: "callData";
|
|
66
|
+
readonly type: "bytes";
|
|
67
|
+
}];
|
|
68
|
+
readonly internalType: "struct Multicall3.Call[]";
|
|
69
|
+
readonly name: "calls";
|
|
70
|
+
readonly type: "tuple[]";
|
|
71
|
+
}];
|
|
72
|
+
readonly name: "aggregate";
|
|
73
|
+
readonly outputs: readonly [{
|
|
74
|
+
readonly internalType: "uint256";
|
|
75
|
+
readonly name: "blockNumber";
|
|
76
|
+
readonly type: "uint256";
|
|
77
|
+
}, {
|
|
78
|
+
readonly internalType: "bytes[]";
|
|
79
|
+
readonly name: "returnData";
|
|
80
|
+
readonly type: "bytes[]";
|
|
81
|
+
}];
|
|
82
|
+
readonly stateMutability: "payable";
|
|
83
|
+
readonly type: "function";
|
|
84
|
+
}, {
|
|
85
|
+
readonly inputs: readonly [{
|
|
86
|
+
readonly components: readonly [{
|
|
87
|
+
readonly internalType: "address";
|
|
88
|
+
readonly name: "target";
|
|
89
|
+
readonly type: "address";
|
|
90
|
+
}, {
|
|
91
|
+
readonly internalType: "bool";
|
|
92
|
+
readonly name: "allowFailure";
|
|
93
|
+
readonly type: "bool";
|
|
94
|
+
}, {
|
|
95
|
+
readonly internalType: "bytes";
|
|
96
|
+
readonly name: "callData";
|
|
97
|
+
readonly type: "bytes";
|
|
98
|
+
}];
|
|
99
|
+
readonly internalType: "struct Multicall3.Call3[]";
|
|
100
|
+
readonly name: "calls";
|
|
101
|
+
readonly type: "tuple[]";
|
|
102
|
+
}];
|
|
103
|
+
readonly name: "aggregate3";
|
|
104
|
+
readonly outputs: readonly [{
|
|
105
|
+
readonly components: readonly [{
|
|
106
|
+
readonly internalType: "bool";
|
|
107
|
+
readonly name: "success";
|
|
108
|
+
readonly type: "bool";
|
|
109
|
+
}, {
|
|
110
|
+
readonly internalType: "bytes";
|
|
111
|
+
readonly name: "returnData";
|
|
112
|
+
readonly type: "bytes";
|
|
113
|
+
}];
|
|
114
|
+
readonly internalType: "struct Multicall3.Result[]";
|
|
115
|
+
readonly name: "returnData";
|
|
116
|
+
readonly type: "tuple[]";
|
|
117
|
+
}];
|
|
118
|
+
readonly stateMutability: "payable";
|
|
119
|
+
readonly type: "function";
|
|
120
|
+
}, {
|
|
121
|
+
readonly inputs: readonly [{
|
|
122
|
+
readonly components: readonly [{
|
|
123
|
+
readonly internalType: "address";
|
|
124
|
+
readonly name: "target";
|
|
125
|
+
readonly type: "address";
|
|
126
|
+
}, {
|
|
127
|
+
readonly internalType: "bool";
|
|
128
|
+
readonly name: "allowFailure";
|
|
129
|
+
readonly type: "bool";
|
|
130
|
+
}, {
|
|
131
|
+
readonly internalType: "uint256";
|
|
132
|
+
readonly name: "value";
|
|
133
|
+
readonly type: "uint256";
|
|
134
|
+
}, {
|
|
135
|
+
readonly internalType: "bytes";
|
|
136
|
+
readonly name: "callData";
|
|
137
|
+
readonly type: "bytes";
|
|
138
|
+
}];
|
|
139
|
+
readonly internalType: "struct Multicall3.Call3Value[]";
|
|
140
|
+
readonly name: "calls";
|
|
141
|
+
readonly type: "tuple[]";
|
|
142
|
+
}];
|
|
143
|
+
readonly name: "aggregate3Value";
|
|
144
|
+
readonly outputs: readonly [{
|
|
145
|
+
readonly components: readonly [{
|
|
146
|
+
readonly internalType: "bool";
|
|
147
|
+
readonly name: "success";
|
|
148
|
+
readonly type: "bool";
|
|
149
|
+
}, {
|
|
150
|
+
readonly internalType: "bytes";
|
|
151
|
+
readonly name: "returnData";
|
|
152
|
+
readonly type: "bytes";
|
|
153
|
+
}];
|
|
154
|
+
readonly internalType: "struct Multicall3.Result[]";
|
|
155
|
+
readonly name: "returnData";
|
|
156
|
+
readonly type: "tuple[]";
|
|
157
|
+
}];
|
|
158
|
+
readonly stateMutability: "payable";
|
|
159
|
+
readonly type: "function";
|
|
160
|
+
}];
|