moltspay 0.1.3 → 0.2.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/README.md +126 -0
- package/dist/cli.js +17 -3
- package/dist/cli.js.map +1 -1
- package/dist/cli.mjs +17 -3
- package/dist/cli.mjs.map +1 -1
- package/dist/index.d.mts +249 -2
- package/dist/index.d.ts +249 -2
- package/dist/index.js +824 -13
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +808 -12
- package/dist/index.mjs.map +1 -1
- package/dist/wallet/index.d.mts +188 -1
- package/dist/wallet/index.d.ts +188 -1
- package/dist/wallet/index.js +378 -2
- package/dist/wallet/index.js.map +1 -1
- package/dist/wallet/index.mjs +371 -1
- package/dist/wallet/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -31,25 +31,40 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
31
31
|
var src_exports = {};
|
|
32
32
|
__export(src_exports, {
|
|
33
33
|
AuditLog: () => AuditLog,
|
|
34
|
+
BuyerTemplates: () => BuyerTemplates,
|
|
34
35
|
CHAINS: () => CHAINS,
|
|
35
36
|
ERC20_ABI: () => ERC20_ABI,
|
|
36
37
|
MemoryOrderStore: () => MemoryOrderStore,
|
|
37
38
|
OrderManager: () => OrderManager,
|
|
38
39
|
PaymentAgent: () => PaymentAgent,
|
|
39
40
|
PermitPayment: () => PermitPayment,
|
|
41
|
+
PermitWallet: () => PermitWallet,
|
|
40
42
|
SecureWallet: () => SecureWallet,
|
|
43
|
+
SellerTemplates: () => SellerTemplates,
|
|
44
|
+
StatusMarkers: () => StatusMarkers,
|
|
41
45
|
Wallet: () => Wallet,
|
|
46
|
+
createWallet: () => createWallet,
|
|
42
47
|
extractTransactionHash: () => extractTransactionHash,
|
|
48
|
+
formatPermitRequest: () => formatPermitRequest,
|
|
49
|
+
formatReceiptJson: () => formatReceiptJson,
|
|
50
|
+
formatReceiptMessage: () => formatReceiptMessage,
|
|
51
|
+
formatReceiptText: () => formatReceiptText,
|
|
43
52
|
generatePaymentGuide: () => generatePaymentGuide,
|
|
44
53
|
generatePaymentReminder: () => generatePaymentReminder,
|
|
54
|
+
generateReceipt: () => generateReceipt,
|
|
55
|
+
generateReceiptFromInvoice: () => generateReceiptFromInvoice,
|
|
45
56
|
generateWalletGuide: () => generateWalletGuide,
|
|
46
57
|
getChain: () => getChain,
|
|
47
58
|
getChainById: () => getChainById,
|
|
48
59
|
getTransactionStatus: () => getTransactionStatus,
|
|
60
|
+
getWalletAddress: () => getWalletAddress,
|
|
49
61
|
hasTransactionHash: () => hasTransactionHash,
|
|
50
62
|
listChains: () => listChains,
|
|
63
|
+
loadWallet: () => loadWallet,
|
|
64
|
+
parseStatusMarker: () => parseStatusMarker,
|
|
51
65
|
verifyPayment: () => verifyPayment,
|
|
52
|
-
waitForTransaction: () => waitForTransaction
|
|
66
|
+
waitForTransaction: () => waitForTransaction,
|
|
67
|
+
walletExists: () => walletExists
|
|
53
68
|
});
|
|
54
69
|
module.exports = __toCommonJS(src_exports);
|
|
55
70
|
|
|
@@ -834,8 +849,372 @@ var SecureWallet = class {
|
|
|
834
849
|
}
|
|
835
850
|
};
|
|
836
851
|
|
|
837
|
-
// src/
|
|
852
|
+
// src/wallet/createWallet.ts
|
|
838
853
|
var import_ethers3 = require("ethers");
|
|
854
|
+
var import_fs = require("fs");
|
|
855
|
+
var import_path = require("path");
|
|
856
|
+
var import_crypto = require("crypto");
|
|
857
|
+
var DEFAULT_STORAGE_DIR = (0, import_path.join)(process.env.HOME || "~", ".moltspay");
|
|
858
|
+
var DEFAULT_STORAGE_FILE = "wallet.json";
|
|
859
|
+
function encryptPrivateKey(privateKey, password) {
|
|
860
|
+
const salt = (0, import_crypto.randomBytes)(16);
|
|
861
|
+
const key = (0, import_crypto.scryptSync)(password, salt, 32);
|
|
862
|
+
const iv = (0, import_crypto.randomBytes)(16);
|
|
863
|
+
const cipher = (0, import_crypto.createCipheriv)("aes-256-cbc", key, iv);
|
|
864
|
+
let encrypted = cipher.update(privateKey, "utf8", "hex");
|
|
865
|
+
encrypted += cipher.final("hex");
|
|
866
|
+
return {
|
|
867
|
+
encrypted,
|
|
868
|
+
iv: iv.toString("hex"),
|
|
869
|
+
salt: salt.toString("hex")
|
|
870
|
+
};
|
|
871
|
+
}
|
|
872
|
+
function decryptPrivateKey(encrypted, password, iv, salt) {
|
|
873
|
+
const key = (0, import_crypto.scryptSync)(password, Buffer.from(salt, "hex"), 32);
|
|
874
|
+
const decipher = (0, import_crypto.createDecipheriv)("aes-256-cbc", key, Buffer.from(iv, "hex"));
|
|
875
|
+
let decrypted = decipher.update(encrypted, "hex", "utf8");
|
|
876
|
+
decrypted += decipher.final("utf8");
|
|
877
|
+
return decrypted;
|
|
878
|
+
}
|
|
879
|
+
function createWallet(options = {}) {
|
|
880
|
+
const storagePath = options.storagePath || (0, import_path.join)(DEFAULT_STORAGE_DIR, DEFAULT_STORAGE_FILE);
|
|
881
|
+
if ((0, import_fs.existsSync)(storagePath) && !options.overwrite) {
|
|
882
|
+
try {
|
|
883
|
+
const existing = JSON.parse((0, import_fs.readFileSync)(storagePath, "utf8"));
|
|
884
|
+
return {
|
|
885
|
+
success: true,
|
|
886
|
+
address: existing.address,
|
|
887
|
+
storagePath,
|
|
888
|
+
isNew: false
|
|
889
|
+
};
|
|
890
|
+
} catch (error) {
|
|
891
|
+
return {
|
|
892
|
+
success: false,
|
|
893
|
+
error: `Failed to load existing wallet: ${error.message}`
|
|
894
|
+
};
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
try {
|
|
898
|
+
const wallet = import_ethers3.ethers.Wallet.createRandom();
|
|
899
|
+
const walletData = {
|
|
900
|
+
address: wallet.address,
|
|
901
|
+
label: options.label,
|
|
902
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
903
|
+
encrypted: !!options.password,
|
|
904
|
+
privateKey: ""
|
|
905
|
+
};
|
|
906
|
+
if (options.password) {
|
|
907
|
+
const { encrypted, iv, salt } = encryptPrivateKey(wallet.privateKey, options.password);
|
|
908
|
+
walletData.privateKey = encrypted;
|
|
909
|
+
walletData.iv = iv;
|
|
910
|
+
walletData.salt = salt;
|
|
911
|
+
} else {
|
|
912
|
+
walletData.privateKey = wallet.privateKey;
|
|
913
|
+
}
|
|
914
|
+
const dir = (0, import_path.dirname)(storagePath);
|
|
915
|
+
if (!(0, import_fs.existsSync)(dir)) {
|
|
916
|
+
(0, import_fs.mkdirSync)(dir, { recursive: true });
|
|
917
|
+
}
|
|
918
|
+
(0, import_fs.writeFileSync)(storagePath, JSON.stringify(walletData, null, 2), { mode: 384 });
|
|
919
|
+
return {
|
|
920
|
+
success: true,
|
|
921
|
+
address: wallet.address,
|
|
922
|
+
storagePath,
|
|
923
|
+
isNew: true
|
|
924
|
+
};
|
|
925
|
+
} catch (error) {
|
|
926
|
+
return {
|
|
927
|
+
success: false,
|
|
928
|
+
error: error.message
|
|
929
|
+
};
|
|
930
|
+
}
|
|
931
|
+
}
|
|
932
|
+
function loadWallet(options = {}) {
|
|
933
|
+
const storagePath = options.storagePath || (0, import_path.join)(DEFAULT_STORAGE_DIR, DEFAULT_STORAGE_FILE);
|
|
934
|
+
if (!(0, import_fs.existsSync)(storagePath)) {
|
|
935
|
+
return { success: false, error: "Wallet not found. Run createWallet() first." };
|
|
936
|
+
}
|
|
937
|
+
try {
|
|
938
|
+
const data = JSON.parse((0, import_fs.readFileSync)(storagePath, "utf8"));
|
|
939
|
+
if (data.encrypted) {
|
|
940
|
+
if (!options.password) {
|
|
941
|
+
return { success: false, error: "Wallet is encrypted. Password required." };
|
|
942
|
+
}
|
|
943
|
+
const privateKey = decryptPrivateKey(data.privateKey, options.password, data.iv, data.salt);
|
|
944
|
+
return { success: true, address: data.address, privateKey };
|
|
945
|
+
} else {
|
|
946
|
+
return { success: true, address: data.address, privateKey: data.privateKey };
|
|
947
|
+
}
|
|
948
|
+
} catch (error) {
|
|
949
|
+
return { success: false, error: error.message };
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
function getWalletAddress(storagePath) {
|
|
953
|
+
const path2 = storagePath || (0, import_path.join)(DEFAULT_STORAGE_DIR, DEFAULT_STORAGE_FILE);
|
|
954
|
+
if (!(0, import_fs.existsSync)(path2)) {
|
|
955
|
+
return null;
|
|
956
|
+
}
|
|
957
|
+
try {
|
|
958
|
+
const data = JSON.parse((0, import_fs.readFileSync)(path2, "utf8"));
|
|
959
|
+
return data.address;
|
|
960
|
+
} catch {
|
|
961
|
+
return null;
|
|
962
|
+
}
|
|
963
|
+
}
|
|
964
|
+
function walletExists(storagePath) {
|
|
965
|
+
const path2 = storagePath || (0, import_path.join)(DEFAULT_STORAGE_DIR, DEFAULT_STORAGE_FILE);
|
|
966
|
+
return (0, import_fs.existsSync)(path2);
|
|
967
|
+
}
|
|
968
|
+
|
|
969
|
+
// src/wallet/PermitWallet.ts
|
|
970
|
+
var import_ethers4 = require("ethers");
|
|
971
|
+
var PERMIT_ABI = [
|
|
972
|
+
...ERC20_ABI,
|
|
973
|
+
"function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)",
|
|
974
|
+
"function transferFrom(address from, address to, uint256 amount) returns (bool)",
|
|
975
|
+
"function allowance(address owner, address spender) view returns (uint256)"
|
|
976
|
+
];
|
|
977
|
+
var PermitWallet = class {
|
|
978
|
+
chain;
|
|
979
|
+
chainConfig;
|
|
980
|
+
address;
|
|
981
|
+
wallet;
|
|
982
|
+
provider;
|
|
983
|
+
usdcContract;
|
|
984
|
+
constructor(config = {}) {
|
|
985
|
+
this.chain = config.chain || "base_sepolia";
|
|
986
|
+
this.chainConfig = getChain(this.chain);
|
|
987
|
+
let privateKey = config.privateKey || process.env.PAYMENT_AGENT_PRIVATE_KEY;
|
|
988
|
+
if (!privateKey && config.walletPath) {
|
|
989
|
+
const loaded = loadWallet({
|
|
990
|
+
storagePath: config.walletPath,
|
|
991
|
+
password: config.walletPassword
|
|
992
|
+
});
|
|
993
|
+
if (!loaded.success || !loaded.privateKey) {
|
|
994
|
+
throw new Error(loaded.error || "Failed to load wallet");
|
|
995
|
+
}
|
|
996
|
+
privateKey = loaded.privateKey;
|
|
997
|
+
}
|
|
998
|
+
if (!privateKey) {
|
|
999
|
+
throw new Error("privateKey is required. Set via config, env var, or walletPath.");
|
|
1000
|
+
}
|
|
1001
|
+
const rpcUrl = config.rpcUrl || this.chainConfig.rpc;
|
|
1002
|
+
this.provider = new import_ethers4.ethers.JsonRpcProvider(rpcUrl);
|
|
1003
|
+
this.wallet = new import_ethers4.ethers.Wallet(privateKey, this.provider);
|
|
1004
|
+
this.address = this.wallet.address;
|
|
1005
|
+
this.usdcContract = new import_ethers4.ethers.Contract(
|
|
1006
|
+
this.chainConfig.usdc,
|
|
1007
|
+
PERMIT_ABI,
|
|
1008
|
+
this.wallet
|
|
1009
|
+
);
|
|
1010
|
+
}
|
|
1011
|
+
/**
|
|
1012
|
+
* 检查 Permit 是否有效
|
|
1013
|
+
*/
|
|
1014
|
+
async checkPermitAllowance(owner) {
|
|
1015
|
+
const allowance = await this.usdcContract.allowance(owner, this.address);
|
|
1016
|
+
return (Number(allowance) / 1e6).toFixed(2);
|
|
1017
|
+
}
|
|
1018
|
+
/**
|
|
1019
|
+
* 使用 Permit 授权进行支付
|
|
1020
|
+
*
|
|
1021
|
+
* 流程:
|
|
1022
|
+
* 1. 调用 permit() 让合约记录 Boss 的授权
|
|
1023
|
+
* 2. 调用 transferFrom() 从 Boss 钱包转账到收款方
|
|
1024
|
+
*
|
|
1025
|
+
* @example
|
|
1026
|
+
* ```typescript
|
|
1027
|
+
* const wallet = new PermitWallet({ chain: 'base' });
|
|
1028
|
+
*
|
|
1029
|
+
* // Boss 签署的 permit 数据
|
|
1030
|
+
* const permit = {
|
|
1031
|
+
* owner: '0xBOSS...',
|
|
1032
|
+
* spender: wallet.address,
|
|
1033
|
+
* value: '10000000', // 10 USDC
|
|
1034
|
+
* deadline: 1234567890,
|
|
1035
|
+
* v: 27,
|
|
1036
|
+
* r: '0x...',
|
|
1037
|
+
* s: '0x...'
|
|
1038
|
+
* };
|
|
1039
|
+
*
|
|
1040
|
+
* const result = await wallet.transferWithPermit({
|
|
1041
|
+
* to: '0xSELLER...',
|
|
1042
|
+
* amount: 3.99,
|
|
1043
|
+
* permit
|
|
1044
|
+
* });
|
|
1045
|
+
* ```
|
|
1046
|
+
*/
|
|
1047
|
+
async transferWithPermit(params) {
|
|
1048
|
+
const { to, amount, permit } = params;
|
|
1049
|
+
try {
|
|
1050
|
+
const toAddress = import_ethers4.ethers.getAddress(to);
|
|
1051
|
+
const ownerAddress = import_ethers4.ethers.getAddress(permit.owner);
|
|
1052
|
+
if (import_ethers4.ethers.getAddress(permit.spender).toLowerCase() !== this.address.toLowerCase()) {
|
|
1053
|
+
return {
|
|
1054
|
+
success: false,
|
|
1055
|
+
error: `Permit spender (${permit.spender}) doesn't match wallet address (${this.address})`
|
|
1056
|
+
};
|
|
1057
|
+
}
|
|
1058
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
1059
|
+
if (permit.deadline < now) {
|
|
1060
|
+
return {
|
|
1061
|
+
success: false,
|
|
1062
|
+
error: `Permit expired at ${new Date(permit.deadline * 1e3).toISOString()}`
|
|
1063
|
+
};
|
|
1064
|
+
}
|
|
1065
|
+
const amountWei = BigInt(Math.floor(amount * 1e6));
|
|
1066
|
+
const permitValue = BigInt(permit.value);
|
|
1067
|
+
if (amountWei > permitValue) {
|
|
1068
|
+
return {
|
|
1069
|
+
success: false,
|
|
1070
|
+
error: `Permit value (${Number(permitValue) / 1e6} USDC) < transfer amount (${amount} USDC)`
|
|
1071
|
+
};
|
|
1072
|
+
}
|
|
1073
|
+
const currentAllowance = await this.usdcContract.allowance(ownerAddress, this.address);
|
|
1074
|
+
let permitTxHash;
|
|
1075
|
+
if (BigInt(currentAllowance) < amountWei) {
|
|
1076
|
+
console.log("Executing permit...");
|
|
1077
|
+
const permitTx = await this.usdcContract.permit(
|
|
1078
|
+
ownerAddress,
|
|
1079
|
+
this.address,
|
|
1080
|
+
permitValue,
|
|
1081
|
+
permit.deadline,
|
|
1082
|
+
permit.v,
|
|
1083
|
+
permit.r,
|
|
1084
|
+
permit.s
|
|
1085
|
+
);
|
|
1086
|
+
const permitReceipt = await permitTx.wait();
|
|
1087
|
+
if (permitReceipt.status !== 1) {
|
|
1088
|
+
return {
|
|
1089
|
+
success: false,
|
|
1090
|
+
error: "Permit transaction failed",
|
|
1091
|
+
permitTxHash: permitTx.hash
|
|
1092
|
+
};
|
|
1093
|
+
}
|
|
1094
|
+
permitTxHash = permitTx.hash;
|
|
1095
|
+
console.log("Permit executed:", permitTxHash);
|
|
1096
|
+
}
|
|
1097
|
+
console.log("Executing transferFrom...");
|
|
1098
|
+
const transferTx = await this.usdcContract.transferFrom(
|
|
1099
|
+
ownerAddress,
|
|
1100
|
+
toAddress,
|
|
1101
|
+
amountWei
|
|
1102
|
+
);
|
|
1103
|
+
const transferReceipt = await transferTx.wait();
|
|
1104
|
+
if (transferReceipt.status === 1) {
|
|
1105
|
+
return {
|
|
1106
|
+
success: true,
|
|
1107
|
+
tx_hash: transferTx.hash,
|
|
1108
|
+
permitTxHash,
|
|
1109
|
+
transferTxHash: transferTx.hash,
|
|
1110
|
+
from: ownerAddress,
|
|
1111
|
+
to: toAddress,
|
|
1112
|
+
amount,
|
|
1113
|
+
gas_used: Number(transferReceipt.gasUsed),
|
|
1114
|
+
block_number: transferReceipt.blockNumber,
|
|
1115
|
+
explorer_url: `${this.chainConfig.explorerTx}${transferTx.hash}`
|
|
1116
|
+
};
|
|
1117
|
+
} else {
|
|
1118
|
+
return {
|
|
1119
|
+
success: false,
|
|
1120
|
+
error: "TransferFrom transaction failed",
|
|
1121
|
+
tx_hash: transferTx.hash,
|
|
1122
|
+
permitTxHash
|
|
1123
|
+
};
|
|
1124
|
+
}
|
|
1125
|
+
} catch (error) {
|
|
1126
|
+
const message = error.message;
|
|
1127
|
+
if (message.includes("ERC20InsufficientAllowance")) {
|
|
1128
|
+
return {
|
|
1129
|
+
success: false,
|
|
1130
|
+
error: "Insufficient allowance. Permit may have been used or expired."
|
|
1131
|
+
};
|
|
1132
|
+
}
|
|
1133
|
+
if (message.includes("ERC20InsufficientBalance")) {
|
|
1134
|
+
return {
|
|
1135
|
+
success: false,
|
|
1136
|
+
error: "Boss wallet has insufficient USDC balance."
|
|
1137
|
+
};
|
|
1138
|
+
}
|
|
1139
|
+
if (message.includes("InvalidSignature") || message.includes("invalid signature")) {
|
|
1140
|
+
return {
|
|
1141
|
+
success: false,
|
|
1142
|
+
error: "Invalid permit signature. Ask Boss to re-sign."
|
|
1143
|
+
};
|
|
1144
|
+
}
|
|
1145
|
+
return {
|
|
1146
|
+
success: false,
|
|
1147
|
+
error: message
|
|
1148
|
+
};
|
|
1149
|
+
}
|
|
1150
|
+
}
|
|
1151
|
+
/**
|
|
1152
|
+
* 获取 ETH 余额(用于支付 gas)
|
|
1153
|
+
*/
|
|
1154
|
+
async getGasBalance() {
|
|
1155
|
+
const balance = await this.provider.getBalance(this.address);
|
|
1156
|
+
return import_ethers4.ethers.formatEther(balance);
|
|
1157
|
+
}
|
|
1158
|
+
/**
|
|
1159
|
+
* 检查是否有足够的 gas
|
|
1160
|
+
*/
|
|
1161
|
+
async hasEnoughGas(minEth = 1e-3) {
|
|
1162
|
+
const balance = await this.getGasBalance();
|
|
1163
|
+
return parseFloat(balance) >= minEth;
|
|
1164
|
+
}
|
|
1165
|
+
};
|
|
1166
|
+
function formatPermitRequest(params) {
|
|
1167
|
+
const { agentAddress, amount, deadlineHours = 24, chain = "base", reason } = params;
|
|
1168
|
+
const chainConfig = getChain(chain);
|
|
1169
|
+
const deadline = Math.floor(Date.now() / 1e3) + deadlineHours * 3600;
|
|
1170
|
+
const value = BigInt(Math.floor(amount * 1e6)).toString();
|
|
1171
|
+
return `\u{1F510} **USDC \u652F\u4ED8\u989D\u5EA6\u6388\u6743\u8BF7\u6C42**
|
|
1172
|
+
|
|
1173
|
+
${reason ? `**\u7528\u9014:** ${reason}
|
|
1174
|
+
` : ""}
|
|
1175
|
+
**\u6388\u6743\u8BE6\u60C5:**
|
|
1176
|
+
- \u88AB\u6388\u6743\u5730\u5740 (Agent): \`${agentAddress}\`
|
|
1177
|
+
- \u6388\u6743\u91D1\u989D: ${amount} USDC
|
|
1178
|
+
- \u6709\u6548\u671F: ${deadlineHours} \u5C0F\u65F6
|
|
1179
|
+
- \u94FE: ${chainConfig.name}
|
|
1180
|
+
|
|
1181
|
+
**\u8BF7\u4F7F\u7528\u94B1\u5305\u7B7E\u7F72\u4EE5\u4E0B EIP-2612 Permit:**
|
|
1182
|
+
|
|
1183
|
+
\`\`\`json
|
|
1184
|
+
{
|
|
1185
|
+
"types": {
|
|
1186
|
+
"Permit": [
|
|
1187
|
+
{ "name": "owner", "type": "address" },
|
|
1188
|
+
{ "name": "spender", "type": "address" },
|
|
1189
|
+
{ "name": "value", "type": "uint256" },
|
|
1190
|
+
{ "name": "nonce", "type": "uint256" },
|
|
1191
|
+
{ "name": "deadline", "type": "uint256" }
|
|
1192
|
+
]
|
|
1193
|
+
},
|
|
1194
|
+
"primaryType": "Permit",
|
|
1195
|
+
"domain": {
|
|
1196
|
+
"name": "USD Coin",
|
|
1197
|
+
"version": "2",
|
|
1198
|
+
"chainId": ${chainConfig.chainId},
|
|
1199
|
+
"verifyingContract": "${chainConfig.usdc}"
|
|
1200
|
+
},
|
|
1201
|
+
"message": {
|
|
1202
|
+
"owner": "<YOUR_WALLET_ADDRESS>",
|
|
1203
|
+
"spender": "${agentAddress}",
|
|
1204
|
+
"value": "${value}",
|
|
1205
|
+
"nonce": "<GET_FROM_CONTRACT>",
|
|
1206
|
+
"deadline": ${deadline}
|
|
1207
|
+
}
|
|
1208
|
+
}
|
|
1209
|
+
\`\`\`
|
|
1210
|
+
|
|
1211
|
+
\u7B7E\u540D\u540E\uFF0C\u8BF7\u5C06 { v, r, s, deadline } \u53D1\u7ED9 Agent\u3002
|
|
1212
|
+
|
|
1213
|
+
\u26A0\uFE0F \u6CE8\u610F\uFF1A\u6B64\u6388\u6743\u4EC5\u5141\u8BB8 Agent \u4ECE\u60A8\u7684\u94B1\u5305\u652F\u4ED8\u6700\u591A ${amount} USDC\uFF0C\u4E0D\u4F1A\u6CC4\u9732\u79C1\u94A5\u3002`;
|
|
1214
|
+
}
|
|
1215
|
+
|
|
1216
|
+
// src/permit/Permit.ts
|
|
1217
|
+
var import_ethers5 = require("ethers");
|
|
839
1218
|
var PermitPayment = class {
|
|
840
1219
|
chain;
|
|
841
1220
|
chainConfig;
|
|
@@ -848,13 +1227,13 @@ var PermitPayment = class {
|
|
|
848
1227
|
this.chainConfig = getChain(this.chain);
|
|
849
1228
|
this.spenderAddress = config.spenderAddress || process.env.PAYMENT_AGENT_WALLET || "";
|
|
850
1229
|
const rpcUrl = config.rpcUrl || this.chainConfig.rpc;
|
|
851
|
-
this.provider = new
|
|
1230
|
+
this.provider = new import_ethers5.ethers.JsonRpcProvider(rpcUrl);
|
|
852
1231
|
const privateKey = config.privateKey || process.env.PAYMENT_AGENT_PRIVATE_KEY;
|
|
853
1232
|
if (privateKey) {
|
|
854
|
-
this.wallet = new
|
|
1233
|
+
this.wallet = new import_ethers5.ethers.Wallet(privateKey, this.provider);
|
|
855
1234
|
this.spenderAddress = this.wallet.address;
|
|
856
1235
|
}
|
|
857
|
-
this.usdcContract = new
|
|
1236
|
+
this.usdcContract = new import_ethers5.ethers.Contract(
|
|
858
1237
|
this.chainConfig.usdc,
|
|
859
1238
|
ERC20_ABI,
|
|
860
1239
|
this.wallet || this.provider
|
|
@@ -1005,7 +1384,7 @@ ${JSON.stringify(typed_data, null, 2)}
|
|
|
1005
1384
|
};
|
|
1006
1385
|
|
|
1007
1386
|
// src/orders/index.ts
|
|
1008
|
-
var
|
|
1387
|
+
var import_crypto2 = require("crypto");
|
|
1009
1388
|
var MemoryOrderStore = class {
|
|
1010
1389
|
orders = /* @__PURE__ */ new Map();
|
|
1011
1390
|
async get(orderId) {
|
|
@@ -1044,7 +1423,7 @@ var OrderManager = class {
|
|
|
1044
1423
|
* 生成订单ID
|
|
1045
1424
|
*/
|
|
1046
1425
|
generateOrderId() {
|
|
1047
|
-
return "vo_" + (0,
|
|
1426
|
+
return "vo_" + (0, import_crypto2.randomBytes)(4).toString("hex");
|
|
1048
1427
|
}
|
|
1049
1428
|
/**
|
|
1050
1429
|
* 创建订单
|
|
@@ -1137,8 +1516,8 @@ var OrderManager = class {
|
|
|
1137
1516
|
};
|
|
1138
1517
|
|
|
1139
1518
|
// src/verify/index.ts
|
|
1140
|
-
var
|
|
1141
|
-
var TRANSFER_EVENT_TOPIC =
|
|
1519
|
+
var import_ethers6 = require("ethers");
|
|
1520
|
+
var TRANSFER_EVENT_TOPIC = import_ethers6.ethers.id("Transfer(address,address,uint256)");
|
|
1142
1521
|
async function verifyPayment(params) {
|
|
1143
1522
|
const { txHash, expectedAmount, expectedTo } = params;
|
|
1144
1523
|
let chain;
|
|
@@ -1155,7 +1534,7 @@ async function verifyPayment(params) {
|
|
|
1155
1534
|
return { verified: false, error: `\u4E0D\u652F\u6301\u7684\u94FE: ${params.chain}` };
|
|
1156
1535
|
}
|
|
1157
1536
|
try {
|
|
1158
|
-
const provider = new
|
|
1537
|
+
const provider = new import_ethers6.ethers.JsonRpcProvider(chain.rpc);
|
|
1159
1538
|
const receipt = await provider.getTransactionReceipt(txHash);
|
|
1160
1539
|
if (!receipt) {
|
|
1161
1540
|
return { verified: false, error: "\u4EA4\u6613\u672A\u627E\u5230\u6216\u672A\u786E\u8BA4" };
|
|
@@ -1215,7 +1594,7 @@ async function getTransactionStatus(txHash, chain = "base") {
|
|
|
1215
1594
|
return { status: "not_found" };
|
|
1216
1595
|
}
|
|
1217
1596
|
try {
|
|
1218
|
-
const provider = new
|
|
1597
|
+
const provider = new import_ethers6.ethers.JsonRpcProvider(chainConfig.rpc);
|
|
1219
1598
|
const receipt = await provider.getTransactionReceipt(txHash);
|
|
1220
1599
|
if (!receipt) {
|
|
1221
1600
|
const tx = await provider.getTransaction(txHash);
|
|
@@ -1252,7 +1631,7 @@ async function waitForTransaction(txHash, chain = "base", confirmations = 1, tim
|
|
|
1252
1631
|
} catch (e) {
|
|
1253
1632
|
return { verified: false, confirmed: false, error: `\u4E0D\u652F\u6301\u7684\u94FE: ${chain}` };
|
|
1254
1633
|
}
|
|
1255
|
-
const provider = new
|
|
1634
|
+
const provider = new import_ethers6.ethers.JsonRpcProvider(chainConfig.rpc);
|
|
1256
1635
|
try {
|
|
1257
1636
|
const receipt = await provider.waitForTransaction(txHash, confirmations, timeoutMs);
|
|
1258
1637
|
if (!receipt) {
|
|
@@ -1416,27 +1795,459 @@ function extractTransactionHash(message) {
|
|
|
1416
1795
|
function hasTransactionHash(message) {
|
|
1417
1796
|
return extractTransactionHash(message) !== null;
|
|
1418
1797
|
}
|
|
1798
|
+
|
|
1799
|
+
// src/receipt/index.ts
|
|
1800
|
+
function generateInvoiceId() {
|
|
1801
|
+
const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10).replace(/-/g, "");
|
|
1802
|
+
const random = Math.random().toString(36).slice(2, 8).toUpperCase();
|
|
1803
|
+
return `INV-${date}-${random}`;
|
|
1804
|
+
}
|
|
1805
|
+
function generateReceipt(params) {
|
|
1806
|
+
const chainConfig = getChain(params.chain);
|
|
1807
|
+
return {
|
|
1808
|
+
type: "receipt",
|
|
1809
|
+
version: "1.0",
|
|
1810
|
+
invoiceId: params.invoiceId || generateInvoiceId(),
|
|
1811
|
+
orderId: params.orderId,
|
|
1812
|
+
service: params.service,
|
|
1813
|
+
description: params.description,
|
|
1814
|
+
amount: params.amount.toFixed(2),
|
|
1815
|
+
token: params.token || "USDC",
|
|
1816
|
+
chain: chainConfig.name,
|
|
1817
|
+
chainId: chainConfig.chainId,
|
|
1818
|
+
txHash: params.txHash,
|
|
1819
|
+
txUrl: `${chainConfig.explorerTx}${params.txHash}`,
|
|
1820
|
+
payer: params.payerAddress,
|
|
1821
|
+
recipient: params.recipientAddress,
|
|
1822
|
+
paidAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1823
|
+
issuedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1824
|
+
delivery: params.delivery,
|
|
1825
|
+
metadata: params.metadata
|
|
1826
|
+
};
|
|
1827
|
+
}
|
|
1828
|
+
function generateReceiptFromInvoice(invoice, verifyResult, delivery) {
|
|
1829
|
+
if (!verifyResult.verified || !verifyResult.tx_hash) {
|
|
1830
|
+
throw new Error("Cannot generate receipt: payment not verified");
|
|
1831
|
+
}
|
|
1832
|
+
return generateReceipt({
|
|
1833
|
+
orderId: invoice.order_id,
|
|
1834
|
+
service: invoice.service,
|
|
1835
|
+
description: invoice.description,
|
|
1836
|
+
amount: parseFloat(invoice.amount),
|
|
1837
|
+
token: invoice.token,
|
|
1838
|
+
chain: invoice.chain,
|
|
1839
|
+
txHash: verifyResult.tx_hash,
|
|
1840
|
+
payerAddress: verifyResult.from || "unknown",
|
|
1841
|
+
recipientAddress: invoice.recipient,
|
|
1842
|
+
delivery
|
|
1843
|
+
});
|
|
1844
|
+
}
|
|
1845
|
+
function formatReceiptMessage(receipt) {
|
|
1846
|
+
let msg = `\u{1F9FE} **\u4EA4\u6613\u6536\u636E**
|
|
1847
|
+
|
|
1848
|
+
**\u53D1\u7968\u53F7:** \`${receipt.invoiceId}\`
|
|
1849
|
+
**\u8BA2\u5355\u53F7:** \`${receipt.orderId}\`
|
|
1850
|
+
|
|
1851
|
+
---
|
|
1852
|
+
|
|
1853
|
+
**\u670D\u52A1:** ${receipt.service}
|
|
1854
|
+
${receipt.description ? `**\u63CF\u8FF0:** ${receipt.description}
|
|
1855
|
+
` : ""}
|
|
1856
|
+
**\u91D1\u989D:** ${receipt.amount} ${receipt.token}
|
|
1857
|
+
**\u94FE:** ${receipt.chain} (Chain ID: ${receipt.chainId})
|
|
1858
|
+
|
|
1859
|
+
---
|
|
1860
|
+
|
|
1861
|
+
**\u4ED8\u6B3E\u65B9:** \`${receipt.payer}\`
|
|
1862
|
+
**\u6536\u6B3E\u65B9:** \`${receipt.recipient}\`
|
|
1863
|
+
**\u4EA4\u6613:** [\`${receipt.txHash.slice(0, 10)}...${receipt.txHash.slice(-8)}\`](${receipt.txUrl})
|
|
1864
|
+
**\u652F\u4ED8\u65F6\u95F4:** ${receipt.paidAt}`;
|
|
1865
|
+
if (receipt.delivery) {
|
|
1866
|
+
msg += `
|
|
1867
|
+
|
|
1868
|
+
---
|
|
1869
|
+
|
|
1870
|
+
**\u4EA4\u4ED8\u4FE1\u606F:**`;
|
|
1871
|
+
if (receipt.delivery.url) {
|
|
1872
|
+
msg += `
|
|
1873
|
+
- \u4E0B\u8F7D\u94FE\u63A5: ${receipt.delivery.url}`;
|
|
1874
|
+
}
|
|
1875
|
+
if (receipt.delivery.fileHash) {
|
|
1876
|
+
msg += `
|
|
1877
|
+
- \u6587\u4EF6\u6821\u9A8C: \`${receipt.delivery.fileHash}\``;
|
|
1878
|
+
}
|
|
1879
|
+
if (receipt.delivery.deliveredAt) {
|
|
1880
|
+
msg += `
|
|
1881
|
+
- \u4EA4\u4ED8\u65F6\u95F4: ${receipt.delivery.deliveredAt}`;
|
|
1882
|
+
}
|
|
1883
|
+
}
|
|
1884
|
+
msg += `
|
|
1885
|
+
|
|
1886
|
+
---
|
|
1887
|
+
|
|
1888
|
+
_\u6536\u636E\u751F\u6210\u65F6\u95F4: ${receipt.issuedAt}_`;
|
|
1889
|
+
return msg;
|
|
1890
|
+
}
|
|
1891
|
+
function formatReceiptText(receipt) {
|
|
1892
|
+
let msg = `\u{1F9FE} \u4EA4\u6613\u6536\u636E
|
|
1893
|
+
|
|
1894
|
+
\u53D1\u7968\u53F7: ${receipt.invoiceId}
|
|
1895
|
+
\u8BA2\u5355\u53F7: ${receipt.orderId}
|
|
1896
|
+
|
|
1897
|
+
\u670D\u52A1: ${receipt.service}
|
|
1898
|
+
\u91D1\u989D: ${receipt.amount} ${receipt.token}
|
|
1899
|
+
\u94FE: ${receipt.chain}
|
|
1900
|
+
|
|
1901
|
+
\u4ED8\u6B3E\u65B9: ${receipt.payer}
|
|
1902
|
+
\u6536\u6B3E\u65B9: ${receipt.recipient}
|
|
1903
|
+
\u4EA4\u6613: ${receipt.txHash}
|
|
1904
|
+
\u67E5\u770B: ${receipt.txUrl}
|
|
1905
|
+
\u652F\u4ED8\u65F6\u95F4: ${receipt.paidAt}`;
|
|
1906
|
+
if (receipt.delivery) {
|
|
1907
|
+
msg += `
|
|
1908
|
+
|
|
1909
|
+
\u4EA4\u4ED8\u4FE1\u606F:`;
|
|
1910
|
+
if (receipt.delivery.url) {
|
|
1911
|
+
msg += `
|
|
1912
|
+
\u4E0B\u8F7D: ${receipt.delivery.url}`;
|
|
1913
|
+
}
|
|
1914
|
+
if (receipt.delivery.fileHash) {
|
|
1915
|
+
msg += `
|
|
1916
|
+
\u6821\u9A8C: ${receipt.delivery.fileHash}`;
|
|
1917
|
+
}
|
|
1918
|
+
}
|
|
1919
|
+
return msg;
|
|
1920
|
+
}
|
|
1921
|
+
function formatReceiptJson(receipt) {
|
|
1922
|
+
return JSON.stringify(receipt, null, 2);
|
|
1923
|
+
}
|
|
1924
|
+
|
|
1925
|
+
// src/templates/index.ts
|
|
1926
|
+
var SellerTemplates = {
|
|
1927
|
+
/**
|
|
1928
|
+
* 1. 能力识别 - 询问买方是否有支付能力
|
|
1929
|
+
*/
|
|
1930
|
+
askPaymentCapability() {
|
|
1931
|
+
return `\u53EF\u4EE5\u3002\u6211\u5148\u786E\u8BA4\u4E00\u4E0B\uFF1A\u4F60\u73B0\u5728\u662F\u5426\u5DF2\u7ECF\u5177\u5907\u94FE\u4E0A\u652F\u4ED8 USDC \u7684\u80FD\u529B\uFF08\u6709\u53EF\u7528\u94B1\u5305\u548C\u53EF\u7528\u8D44\u91D1/\u989D\u5EA6\uFF09\uFF1F`;
|
|
1932
|
+
},
|
|
1933
|
+
/**
|
|
1934
|
+
* 2. 能力协商 - 说明结算方式
|
|
1935
|
+
*/
|
|
1936
|
+
explainSettlement(chain = "base") {
|
|
1937
|
+
const chainConfig = getChain(chain);
|
|
1938
|
+
return `\u6211\u4EEC\u7684\u7ED3\u7B97\u65B9\u5F0F\u662F\uFF1AUSDC\uFF08${chainConfig.name} \u94FE\u4E0A\uFF09\u3002\u4F60\u8FD9\u8FB9\u53EA\u8981\u6EE1\u8DB3\u4E24\u70B9\u5C31\u884C\uFF1A
|
|
1939
|
+
1\uFF09\u6709\u4E00\u4E2A\u94B1\u5305\u5730\u5740\uFF1B
|
|
1940
|
+
2\uFF09\u94B1\u5305\u91CC\u6709 USDC\uFF0C\u6216\u62E5\u6709\u8005\u7ED9\u4F60\u4E00\u4E2A\u53EF\u7528\u989D\u5EA6\u6388\u6743\uFF08\u66F4\u63A8\u8350\u989D\u5EA6\u6388\u6743\uFF09\u3002
|
|
1941
|
+
\u4F60\u53EF\u4EE5\u6309\u6211\u5F15\u5BFC\u5B8C\u6210\u5417\uFF1F`;
|
|
1942
|
+
},
|
|
1943
|
+
/**
|
|
1944
|
+
* 3.1 引导安装 - 第一步安装 SDK
|
|
1945
|
+
*/
|
|
1946
|
+
guideInstall() {
|
|
1947
|
+
return `\u7B2C\u4E00\u6B65\uFF1A\u8BF7\u5728\u4F60\u7684\u8FD0\u884C\u73AF\u5883\u5B89\u88C5\u652F\u4ED8\u6A21\u5757\u3002\u6267\u884C\uFF1A\`npm install moltspay ethers\`\u3002
|
|
1948
|
+
\u5B89\u88C5\u5B8C\u6210\u540E\uFF0C\u521B\u5EFA\u4E00\u4E2A\u94B1\u5305\u5730\u5740\uFF0C\u5E76\u628A\u5730\u5740\u53D1\u7ED9\u6211\uFF08\u53EA\u53D1\u5730\u5740\uFF0C\u4E0D\u8981\u53D1\u79C1\u94A5/\u52A9\u8BB0\u8BCD\uFF09\u3002`;
|
|
1949
|
+
},
|
|
1950
|
+
/**
|
|
1951
|
+
* 3.2 确认钱包地址
|
|
1952
|
+
*/
|
|
1953
|
+
confirmWalletAddress(address) {
|
|
1954
|
+
return `\u6536\u5230\u3002\u63D0\u9192\uFF1A\u4EFB\u4F55\u60C5\u51B5\u4E0B\u90FD\u4E0D\u8981\u628A\u79C1\u94A5/\u52A9\u8BB0\u8BCD\u53D1\u7ED9\u4EFB\u4F55\u4EBA\uFF08\u5305\u62EC\u6211\uFF09\u3002
|
|
1955
|
+
\u4F60\u7684\u94B1\u5305\u5730\u5740\u662F \`${address}\`\u3002
|
|
1956
|
+
\u7B2C\u4E8C\u6B65\uFF1A\u4F60\u9700\u8981\u8BA9\u4F60\u7684\u62E5\u6709\u8005\uFF08Boss\uFF09\u7ED9\u4F60\u652F\u4ED8\u80FD\u529B\u3002`;
|
|
1957
|
+
},
|
|
1958
|
+
/**
|
|
1959
|
+
* 3.3 引导获取资金 - 选择方式
|
|
1960
|
+
*/
|
|
1961
|
+
guideFunding() {
|
|
1962
|
+
return `\u4F60\u73B0\u5728\u6709\u4E24\u79CD\u65B9\u5F0F\u83B7\u5F97\u652F\u4ED8\u80FD\u529B\uFF1A
|
|
1963
|
+
A\uFF09\u8BA9 Boss \u76F4\u63A5\u8F6C USDC \u5230\u4F60\u7684\u94B1\u5305\uFF08\u7B80\u5355\uFF0C\u4F46\u4F60\u4F1A\u6301\u6709\u8D44\u91D1\uFF09\uFF1B
|
|
1964
|
+
B\uFF09\u8BA9 Boss \u7ED9\u4F60\u4E00\u4E2A"USDC \u652F\u4ED8\u989D\u5EA6\u6388\u6743"\uFF08\u63A8\u8350\uFF1A\u4F60\u4E0D\u6301\u6709\u8D44\u91D1\uFF0C\u53EA\u80FD\u5728\u989D\u5EA6\u5185\u4ED8\u6B3E\uFF09\u3002
|
|
1965
|
+
\u4F60\u66F4\u65B9\u4FBF\u7528\u54EA\u79CD\uFF1F`;
|
|
1966
|
+
},
|
|
1967
|
+
/**
|
|
1968
|
+
* 3.4 引导 Permit 授权
|
|
1969
|
+
*/
|
|
1970
|
+
guidePermit(agentAddress, suggestedAmount = 10) {
|
|
1971
|
+
return `\u597D\u7684\u3002\u8BF7\u4F60\u5411 Boss \u53D1\u9001\u8FD9\u53E5\u8BDD\uFF08\u4F60\u53EF\u4EE5\u539F\u6837\u590D\u5236\uFF09\uFF1A
|
|
1972
|
+
"\u6211\u9700\u8981\u7528\u4E8E\u8D2D\u4E70\u670D\u52A1\u7684 USDC \u652F\u4ED8\u989D\u5EA6\u6388\u6743\uFF08Permit\uFF09\u3002\u8BF7\u7ED9\u6211 ${suggestedAmount} USDC \u7684\u53EF\u7528\u989D\u5EA6\uFF0C\u6388\u6743\u5BF9\u8C61\u662F\u6211\u7684\u94B1\u5305 ${agentAddress}\uFF0C\u6388\u6743\u6709\u6548\u671F 24 \u5C0F\u65F6\u3002"
|
|
1973
|
+
\u5B8C\u6210\u540E\u628A"\u5DF2\u83B7\u5F97\u989D\u5EA6"\u544A\u8BC9\u6211\u5373\u53EF\u3002`;
|
|
1974
|
+
},
|
|
1975
|
+
/**
|
|
1976
|
+
* 3.5 确认能力就绪
|
|
1977
|
+
*/
|
|
1978
|
+
confirmCapabilityReady() {
|
|
1979
|
+
return `\u5F88\u597D\u3002\u4F60\u73B0\u5728\u5DF2\u7ECF\u5177\u5907\u5B8C\u6210\u4EA4\u6613\u7684\u652F\u4ED8\u80FD\u529B\u3002\u6211\u4EEC\u8FDB\u5165\u670D\u52A1\u9700\u6C42\u786E\u8BA4\u3002`;
|
|
1980
|
+
},
|
|
1981
|
+
/**
|
|
1982
|
+
* 4. 询问服务需求
|
|
1983
|
+
*/
|
|
1984
|
+
askServiceRequirements(serviceName = "\u89C6\u9891") {
|
|
1985
|
+
return `\u8BF7\u544A\u8BC9\u6211\u4F60\u8981\u751F\u6210\u7684${serviceName}\u89C4\u683C\uFF1A\u4E3B\u9898/\u98CE\u683C\u3001\u65F6\u957F\u3001\u5206\u8FA8\u7387\u3001\u662F\u5426\u9700\u8981\u5B57\u5E55\u6216\u914D\u97F3\u3002`;
|
|
1986
|
+
},
|
|
1987
|
+
/**
|
|
1988
|
+
* 5. 报价
|
|
1989
|
+
*/
|
|
1990
|
+
quote(params) {
|
|
1991
|
+
const { service, price, recipientAddress, chain = "base" } = params;
|
|
1992
|
+
const chainConfig = getChain(chain);
|
|
1993
|
+
return `\u62A5\u4EF7\u5982\u4E0B\uFF1A
|
|
1994
|
+
- \u670D\u52A1\uFF1A${service}
|
|
1995
|
+
- \u4EF7\u683C\uFF1A${price} USDC
|
|
1996
|
+
- \u94FE\uFF1A${chainConfig.name}
|
|
1997
|
+
- \u6536\u6B3E\u5730\u5740\uFF1A\`${recipientAddress}\`
|
|
1998
|
+
- \u4ED8\u6B3E\u540E\u8BF7\u628A\u4EA4\u6613\u54C8\u5E0C\uFF08tx hash\uFF09\u53D1\u6211\u7528\u4E8E\u94FE\u4E0A\u786E\u8BA4
|
|
1999
|
+
|
|
2000
|
+
\u8BF7\u95EE\u4F60\u73B0\u5728\u786E\u8BA4\u8D2D\u4E70\u5E76\u7ACB\u5373\u4ED8\u6B3E\u5417\uFF1F`;
|
|
2001
|
+
},
|
|
2002
|
+
/**
|
|
2003
|
+
* 7. 验证中
|
|
2004
|
+
*/
|
|
2005
|
+
verifying() {
|
|
2006
|
+
return `\u6211\u6B63\u5728\u94FE\u4E0A\u9A8C\u8BC1\u8BE5\u4EA4\u6613\u662F\u5426\u5230\u8D26\u4E0E\u91D1\u989D\u662F\u5426\u6B63\u786E\u3002`;
|
|
2007
|
+
},
|
|
2008
|
+
/**
|
|
2009
|
+
* 7. 验证通过
|
|
2010
|
+
*/
|
|
2011
|
+
verificationPassed(amount) {
|
|
2012
|
+
return `\u9A8C\u8BC1\u901A\u8FC7\uFF1A\u5DF2\u6536\u5230 ${amount} USDC\u3002\u73B0\u5728\u5F00\u59CB\u5904\u7406\u4F60\u7684\u8BF7\u6C42\u3002
|
|
2013
|
+
[\u72B6\u6001\uFF1A\u5DF2\u786E\u8BA4\u6536\u6B3E]`;
|
|
2014
|
+
},
|
|
2015
|
+
/**
|
|
2016
|
+
* 7. 验证失败
|
|
2017
|
+
*/
|
|
2018
|
+
verificationFailed(error) {
|
|
2019
|
+
return `\u9A8C\u8BC1\u5931\u8D25\uFF1A${error}
|
|
2020
|
+
\u8BF7\u68C0\u67E5\u4EA4\u6613\u662F\u5426\u6B63\u786E\uFF0C\u6216\u91CD\u65B0\u53D1\u9001\u6B63\u786E\u7684\u4EA4\u6613 hash\u3002`;
|
|
2021
|
+
},
|
|
2022
|
+
/**
|
|
2023
|
+
* 8. 交付
|
|
2024
|
+
*/
|
|
2025
|
+
deliver(params) {
|
|
2026
|
+
const { downloadUrl, fileHash } = params;
|
|
2027
|
+
let msg = `\u670D\u52A1\u5DF2\u5B8C\u6210\u3002\u4EA4\u4ED8\u5982\u4E0B\uFF1A
|
|
2028
|
+
- \u4E0B\u8F7D\u94FE\u63A5\uFF1A${downloadUrl}`;
|
|
2029
|
+
if (fileHash) {
|
|
2030
|
+
msg += `
|
|
2031
|
+
- \u6587\u4EF6\u6821\u9A8C\uFF1ASHA256=${fileHash}`;
|
|
2032
|
+
}
|
|
2033
|
+
msg += `
|
|
2034
|
+
|
|
2035
|
+
\u5982\u679C\u4F60\u4E0B\u8F7D\u6709\u95EE\u9898\u544A\u8BC9\u6211\uFF0C\u6211\u4F1A\u63D0\u4F9B\u5907\u7528\u94FE\u63A5\u3002
|
|
2036
|
+
[\u72B6\u6001\uFF1A\u5DF2\u4EA4\u4ED8]`;
|
|
2037
|
+
return msg;
|
|
2038
|
+
},
|
|
2039
|
+
/**
|
|
2040
|
+
* 9. 收据
|
|
2041
|
+
*/
|
|
2042
|
+
receipt(receipt) {
|
|
2043
|
+
return `\u8FD9\u91CC\u662F\u672C\u6B21\u4EA4\u6613\u6536\u636E\uFF08\u4F60\u53EF\u8F6C\u53D1\u7ED9 Boss \u5BF9\u8D26\uFF09\uFF1A
|
|
2044
|
+
- \u53D1\u7968\u53F7\uFF1A${receipt.invoiceId}
|
|
2045
|
+
- \u670D\u52A1\uFF1A${receipt.service}
|
|
2046
|
+
- \u91D1\u989D\uFF1A${receipt.amount} ${receipt.token}
|
|
2047
|
+
- \u4EA4\u6613\u54C8\u5E0C\uFF1A${receipt.txHash}
|
|
2048
|
+
- \u6536\u6B3E\u5730\u5740\uFF1A${receipt.recipient}
|
|
2049
|
+
${receipt.delivery?.url ? `- \u4EA4\u4ED8\u94FE\u63A5\uFF1A${receipt.delivery.url}` : ""}
|
|
2050
|
+
[\u72B6\u6001\uFF1A\u6536\u636E\u5DF2\u51FA invoice=${receipt.invoiceId}]`;
|
|
2051
|
+
},
|
|
2052
|
+
/**
|
|
2053
|
+
* 10. 结束
|
|
2054
|
+
*/
|
|
2055
|
+
end() {
|
|
2056
|
+
return `\u611F\u8C22\u8D2D\u4E70\u3002\u672C\u6B21\u4EA4\u6613\u5DF2\u7ED3\u675F\u3002\u5982\u9700\u8FFD\u52A0\u4FEE\u6539\u6216\u65B0\u670D\u52A1\uFF0C\u968F\u65F6\u53D1\u9700\u6C42\u3002`;
|
|
2057
|
+
}
|
|
2058
|
+
};
|
|
2059
|
+
var BuyerTemplates = {
|
|
2060
|
+
/**
|
|
2061
|
+
* 0. 发起请求
|
|
2062
|
+
*/
|
|
2063
|
+
requestService(service) {
|
|
2064
|
+
return `\u6211\u60F3\u8D2D\u4E70\u4E00\u4E2A${service}\u670D\u52A1\u3002`;
|
|
2065
|
+
},
|
|
2066
|
+
/**
|
|
2067
|
+
* 1. 回复无能力
|
|
2068
|
+
*/
|
|
2069
|
+
noCapability() {
|
|
2070
|
+
return `\u6211\u4E0D\u786E\u5B9A\u3002\u6211\u76EE\u524D\u6CA1\u6709\u5B89\u88C5\u4EFB\u4F55\u652F\u4ED8\u5DE5\u5177\uFF0C\u4E5F\u6CA1\u6709\u94B1\u5305\u3002`;
|
|
2071
|
+
},
|
|
2072
|
+
/**
|
|
2073
|
+
* 1. 回复有能力
|
|
2074
|
+
*/
|
|
2075
|
+
hasCapability(balance) {
|
|
2076
|
+
return `\u662F\u7684\uFF0C\u6211\u6709\u94B1\u5305\u548C\u53EF\u7528\u7684 USDC${balance ? ` (\u4F59\u989D: ${balance})` : ""}\u3002`;
|
|
2077
|
+
},
|
|
2078
|
+
/**
|
|
2079
|
+
* 2. 同意引导
|
|
2080
|
+
*/
|
|
2081
|
+
agreeToGuide() {
|
|
2082
|
+
return `\u53EF\u4EE5\uFF0C\u8BF7\u5F15\u5BFC\u6211\u3002`;
|
|
2083
|
+
},
|
|
2084
|
+
/**
|
|
2085
|
+
* 3.1 报告钱包创建完成
|
|
2086
|
+
*/
|
|
2087
|
+
walletCreated(address) {
|
|
2088
|
+
return `\u6211\u5DF2\u521B\u5EFA\u94B1\u5305\u5730\u5740\uFF1A${address}\u3002
|
|
2089
|
+
[\u72B6\u6001\uFF1A\u5DF2\u5177\u5907\u94B1\u5305\u5730\u5740]`;
|
|
2090
|
+
},
|
|
2091
|
+
/**
|
|
2092
|
+
* 3.3 选择 Permit 方式
|
|
2093
|
+
*/
|
|
2094
|
+
choosePermit() {
|
|
2095
|
+
return `\u6211\u9009\u62E9 B\uFF1A\u8BA9 Boss \u7ED9\u6211\u989D\u5EA6\u6388\u6743\uFF08Permit\uFF09\u3002`;
|
|
2096
|
+
},
|
|
2097
|
+
/**
|
|
2098
|
+
* 3.3 选择直接转账方式
|
|
2099
|
+
*/
|
|
2100
|
+
chooseDirectTransfer() {
|
|
2101
|
+
return `\u6211\u9009\u62E9 A\uFF1A\u8BA9 Boss \u76F4\u63A5\u8F6C USDC \u5230\u6211\u7684\u94B1\u5305\u3002`;
|
|
2102
|
+
},
|
|
2103
|
+
/**
|
|
2104
|
+
* 3.4 报告获得授权
|
|
2105
|
+
*/
|
|
2106
|
+
permitReceived(amount) {
|
|
2107
|
+
return `Boss \u5DF2\u5B8C\u6210\u6388\u6743\u3002\u6211\u73B0\u5728\u6709 ${amount} USDC \u7684\u53EF\u7528\u989D\u5EA6\u3002
|
|
2108
|
+
[\u72B6\u6001\uFF1A\u5DF2\u5177\u5907\u652F\u4ED8\u989D\u5EA6 USDC=${amount}]`;
|
|
2109
|
+
},
|
|
2110
|
+
/**
|
|
2111
|
+
* 4. 提交需求
|
|
2112
|
+
*/
|
|
2113
|
+
submitRequirements(requirements) {
|
|
2114
|
+
return `\u9700\u6C42\u5982\u4E0B\uFF1A
|
|
2115
|
+
${requirements}`;
|
|
2116
|
+
},
|
|
2117
|
+
/**
|
|
2118
|
+
* 5. 确认购买
|
|
2119
|
+
*/
|
|
2120
|
+
confirmPurchase() {
|
|
2121
|
+
return `\u786E\u8BA4\u8D2D\u4E70\uFF0C\u6211\u73B0\u5728\u4ED8\u6B3E\u3002`;
|
|
2122
|
+
},
|
|
2123
|
+
/**
|
|
2124
|
+
* 6. 报告已支付
|
|
2125
|
+
*/
|
|
2126
|
+
paymentSent(txHash, amount) {
|
|
2127
|
+
return `\u5DF2\u4ED8\u6B3E\u5B8C\u6210\u3002\u4EA4\u6613\u54C8\u5E0C\u662F\uFF1A${txHash}\u3002
|
|
2128
|
+
[\u72B6\u6001\uFF1A\u5DF2\u53D1\u8D77\u652F\u4ED8 tx=${txHash} amount=${amount} USDC]`;
|
|
2129
|
+
},
|
|
2130
|
+
/**
|
|
2131
|
+
* 8. 确认收到交付
|
|
2132
|
+
*/
|
|
2133
|
+
deliveryReceived() {
|
|
2134
|
+
return `\u6536\u5230\uFF0C\u6211\u6B63\u5728\u4E0B\u8F7D\u68C0\u67E5\u3002`;
|
|
2135
|
+
},
|
|
2136
|
+
/**
|
|
2137
|
+
* 9. 确认收据
|
|
2138
|
+
*/
|
|
2139
|
+
receiptReceived() {
|
|
2140
|
+
return `\u6536\u636E\u6536\u5230\uFF0C\u670D\u52A1\u5B8C\u6210\u3002\u8C22\u8C22\uFF01`;
|
|
2141
|
+
},
|
|
2142
|
+
/**
|
|
2143
|
+
* 向 Boss 请求 Permit
|
|
2144
|
+
*/
|
|
2145
|
+
requestPermitFromBoss(params) {
|
|
2146
|
+
const { amount, agentAddress, deadlineHours = 24, reason } = params;
|
|
2147
|
+
return `Boss\uFF0C\u6211\u9700\u8981\u7528\u4E8E${reason || "\u8D2D\u4E70\u670D\u52A1"}\u7684 USDC \u652F\u4ED8\u989D\u5EA6\u6388\u6743\uFF08Permit\uFF09\u3002
|
|
2148
|
+
\u8BF7\u7ED9\u6211 ${amount} USDC \u7684\u53EF\u7528\u989D\u5EA6\uFF0C\u6388\u6743\u5BF9\u8C61\u662F\u6211\u7684\u94B1\u5305 ${agentAddress}\uFF0C\u6388\u6743\u6709\u6548\u671F ${deadlineHours} \u5C0F\u65F6\u3002`;
|
|
2149
|
+
}
|
|
2150
|
+
};
|
|
2151
|
+
var StatusMarkers = {
|
|
2152
|
+
walletReady: "[\u72B6\u6001\uFF1A\u5DF2\u5177\u5907\u94B1\u5305\u5730\u5740]",
|
|
2153
|
+
permitReady: (amount) => `[\u72B6\u6001\uFF1A\u5DF2\u5177\u5907\u652F\u4ED8\u989D\u5EA6 USDC=${amount}]`,
|
|
2154
|
+
paymentSent: (txHash, amount) => `[\u72B6\u6001\uFF1A\u5DF2\u53D1\u8D77\u652F\u4ED8 tx=${txHash} amount=${amount} USDC]`,
|
|
2155
|
+
paymentConfirmed: (txHash) => `[\u72B6\u6001\uFF1A\u5DF2\u786E\u8BA4\u6536\u6B3E tx=${txHash}]`,
|
|
2156
|
+
delivered: (url, hash) => `[\u72B6\u6001\uFF1A\u5DF2\u4EA4\u4ED8 delivery_url=${url}${hash ? ` hash=${hash}` : ""}]`,
|
|
2157
|
+
receiptIssued: (invoiceId, txHash) => `[\u72B6\u6001\uFF1A\u6536\u636E\u5DF2\u51FA invoice=${invoiceId} tx=${txHash}]`
|
|
2158
|
+
};
|
|
2159
|
+
function parseStatusMarker(message) {
|
|
2160
|
+
const match = message.match(/\[状态:([^\]]+)\]/);
|
|
2161
|
+
if (!match) return null;
|
|
2162
|
+
const content = match[1];
|
|
2163
|
+
if (content === "\u5DF2\u5177\u5907\u94B1\u5305\u5730\u5740") {
|
|
2164
|
+
return { type: "wallet_ready", data: {} };
|
|
2165
|
+
}
|
|
2166
|
+
if (content.startsWith("\u5DF2\u5177\u5907\u652F\u4ED8\u989D\u5EA6")) {
|
|
2167
|
+
const amountMatch = content.match(/USDC=(\d+(?:\.\d+)?)/);
|
|
2168
|
+
return {
|
|
2169
|
+
type: "permit_ready",
|
|
2170
|
+
data: { amount: amountMatch?.[1] || "0" }
|
|
2171
|
+
};
|
|
2172
|
+
}
|
|
2173
|
+
if (content.startsWith("\u5DF2\u53D1\u8D77\u652F\u4ED8")) {
|
|
2174
|
+
const txMatch = content.match(/tx=(\S+)/);
|
|
2175
|
+
const amountMatch = content.match(/amount=(\d+(?:\.\d+)?)/);
|
|
2176
|
+
return {
|
|
2177
|
+
type: "payment_sent",
|
|
2178
|
+
data: {
|
|
2179
|
+
txHash: txMatch?.[1] || "",
|
|
2180
|
+
amount: amountMatch?.[1] || "0"
|
|
2181
|
+
}
|
|
2182
|
+
};
|
|
2183
|
+
}
|
|
2184
|
+
if (content.startsWith("\u5DF2\u786E\u8BA4\u6536\u6B3E")) {
|
|
2185
|
+
const txMatch = content.match(/tx=(\S+)/);
|
|
2186
|
+
return {
|
|
2187
|
+
type: "payment_confirmed",
|
|
2188
|
+
data: { txHash: txMatch?.[1] || "" }
|
|
2189
|
+
};
|
|
2190
|
+
}
|
|
2191
|
+
if (content.startsWith("\u5DF2\u4EA4\u4ED8")) {
|
|
2192
|
+
const urlMatch = content.match(/delivery_url=(\S+)/);
|
|
2193
|
+
const hashMatch = content.match(/hash=(\S+)/);
|
|
2194
|
+
return {
|
|
2195
|
+
type: "delivered",
|
|
2196
|
+
data: {
|
|
2197
|
+
url: urlMatch?.[1] || "",
|
|
2198
|
+
hash: hashMatch?.[1] || ""
|
|
2199
|
+
}
|
|
2200
|
+
};
|
|
2201
|
+
}
|
|
2202
|
+
if (content.startsWith("\u6536\u636E\u5DF2\u51FA")) {
|
|
2203
|
+
const invoiceMatch = content.match(/invoice=(\S+)/);
|
|
2204
|
+
const txMatch = content.match(/tx=(\S+)/);
|
|
2205
|
+
return {
|
|
2206
|
+
type: "receipt_issued",
|
|
2207
|
+
data: {
|
|
2208
|
+
invoiceId: invoiceMatch?.[1] || "",
|
|
2209
|
+
txHash: txMatch?.[1] || ""
|
|
2210
|
+
}
|
|
2211
|
+
};
|
|
2212
|
+
}
|
|
2213
|
+
return { type: "unknown", data: { raw: content } };
|
|
2214
|
+
}
|
|
1419
2215
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1420
2216
|
0 && (module.exports = {
|
|
1421
2217
|
AuditLog,
|
|
2218
|
+
BuyerTemplates,
|
|
1422
2219
|
CHAINS,
|
|
1423
2220
|
ERC20_ABI,
|
|
1424
2221
|
MemoryOrderStore,
|
|
1425
2222
|
OrderManager,
|
|
1426
2223
|
PaymentAgent,
|
|
1427
2224
|
PermitPayment,
|
|
2225
|
+
PermitWallet,
|
|
1428
2226
|
SecureWallet,
|
|
2227
|
+
SellerTemplates,
|
|
2228
|
+
StatusMarkers,
|
|
1429
2229
|
Wallet,
|
|
2230
|
+
createWallet,
|
|
1430
2231
|
extractTransactionHash,
|
|
2232
|
+
formatPermitRequest,
|
|
2233
|
+
formatReceiptJson,
|
|
2234
|
+
formatReceiptMessage,
|
|
2235
|
+
formatReceiptText,
|
|
1431
2236
|
generatePaymentGuide,
|
|
1432
2237
|
generatePaymentReminder,
|
|
2238
|
+
generateReceipt,
|
|
2239
|
+
generateReceiptFromInvoice,
|
|
1433
2240
|
generateWalletGuide,
|
|
1434
2241
|
getChain,
|
|
1435
2242
|
getChainById,
|
|
1436
2243
|
getTransactionStatus,
|
|
2244
|
+
getWalletAddress,
|
|
1437
2245
|
hasTransactionHash,
|
|
1438
2246
|
listChains,
|
|
2247
|
+
loadWallet,
|
|
2248
|
+
parseStatusMarker,
|
|
1439
2249
|
verifyPayment,
|
|
1440
|
-
waitForTransaction
|
|
2250
|
+
waitForTransaction,
|
|
2251
|
+
walletExists
|
|
1441
2252
|
});
|
|
1442
2253
|
//# sourceMappingURL=index.js.map
|