moltspay 0.1.3 → 0.2.1
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/guide/index.d.mts +7 -7
- package/dist/guide/index.d.ts +7 -7
- package/dist/guide/index.js +50 -50
- package/dist/guide/index.js.map +1 -1
- package/dist/guide/index.mjs +50 -50
- package/dist/guide/index.mjs.map +1 -1
- package/dist/index.d.mts +249 -2
- package/dist/index.d.ts +249 -2
- package/dist/index.js +874 -63
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +858 -62
- 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
|
+
* Check if Permit is valid (current allowance)
|
|
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
|
+
* Pay using Permit authorization
|
|
1020
|
+
*
|
|
1021
|
+
* Flow:
|
|
1022
|
+
* 1. Call permit() to record Boss's authorization in the contract
|
|
1023
|
+
* 2. Call transferFrom() to transfer from Boss's wallet to recipient
|
|
1024
|
+
*
|
|
1025
|
+
* @example
|
|
1026
|
+
* ```typescript
|
|
1027
|
+
* const wallet = new PermitWallet({ chain: 'base' });
|
|
1028
|
+
*
|
|
1029
|
+
* // Boss-signed permit data
|
|
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
|
+
* Get ETH balance (for gas)
|
|
1153
|
+
*/
|
|
1154
|
+
async getGasBalance() {
|
|
1155
|
+
const balance = await this.provider.getBalance(this.address);
|
|
1156
|
+
return import_ethers4.ethers.formatEther(balance);
|
|
1157
|
+
}
|
|
1158
|
+
/**
|
|
1159
|
+
* Check if there's enough 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 Spending Allowance Request**
|
|
1172
|
+
|
|
1173
|
+
${reason ? `**Purpose:** ${reason}
|
|
1174
|
+
` : ""}
|
|
1175
|
+
**Authorization Details:**
|
|
1176
|
+
- Authorized address (Agent): \`${agentAddress}\`
|
|
1177
|
+
- Amount: ${amount} USDC
|
|
1178
|
+
- Valid for: ${deadlineHours} hours
|
|
1179
|
+
- Chain: ${chainConfig.name}
|
|
1180
|
+
|
|
1181
|
+
**Please sign the following EIP-2612 Permit with your wallet:**
|
|
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
|
+
After signing, send { v, r, s, deadline } to the Agent.
|
|
1212
|
+
|
|
1213
|
+
\u26A0\uFE0F Note: This authorization only allows the Agent to spend up to ${amount} USDC from your wallet. Your private key is never exposed.`;
|
|
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) {
|
|
@@ -1280,131 +1659,131 @@ function generatePaymentGuide(params) {
|
|
|
1280
1659
|
price,
|
|
1281
1660
|
recipientAddress,
|
|
1282
1661
|
chain = "base",
|
|
1283
|
-
serviceName = "
|
|
1662
|
+
serviceName = "Video Generation Service"
|
|
1284
1663
|
} = params;
|
|
1285
1664
|
const chainId = chain === "base" ? 8453 : 84532;
|
|
1286
|
-
const chainName = chain === "base" ? "Base
|
|
1665
|
+
const chainName = chain === "base" ? "Base Mainnet" : "Base Sepolia Testnet";
|
|
1287
1666
|
const explorer = chain === "base" ? "https://basescan.org/tx/" : "https://sepolia.basescan.org/tx/";
|
|
1288
1667
|
return `\u{1F3AC} **${serviceName}**
|
|
1289
1668
|
|
|
1290
|
-
\u{1F4CB}
|
|
1291
|
-
-
|
|
1292
|
-
-
|
|
1293
|
-
-
|
|
1294
|
-
-
|
|
1669
|
+
\u{1F4CB} **Order Details:**
|
|
1670
|
+
- Order ID: \`${orderId}\`
|
|
1671
|
+
- Content: ${prompt.length > 50 ? prompt.slice(0, 50) + "..." : prompt}
|
|
1672
|
+
- Price: **${price} USDC**
|
|
1673
|
+
- Chain: ${chainName}
|
|
1295
1674
|
|
|
1296
1675
|
---
|
|
1297
1676
|
|
|
1298
|
-
## \u{1F4B3}
|
|
1677
|
+
## \u{1F4B3} How to Pay
|
|
1299
1678
|
|
|
1300
|
-
###
|
|
1679
|
+
### Option 1: Install moltspay SDK (Recommended)
|
|
1301
1680
|
|
|
1302
1681
|
\`\`\`bash
|
|
1303
1682
|
npm install moltspay ethers
|
|
1304
1683
|
\`\`\`
|
|
1305
1684
|
|
|
1306
|
-
|
|
1685
|
+
**Create wallet and pay:**
|
|
1307
1686
|
|
|
1308
1687
|
\`\`\`javascript
|
|
1309
1688
|
const { SecureWallet, getChain } = require('moltspay');
|
|
1310
1689
|
const { Wallet } = require('ethers');
|
|
1311
1690
|
|
|
1312
|
-
// 1.
|
|
1691
|
+
// 1. Create new wallet (first time)
|
|
1313
1692
|
const newWallet = Wallet.createRandom();
|
|
1314
|
-
console.log('
|
|
1315
|
-
console.log('
|
|
1693
|
+
console.log('Wallet address:', newWallet.address);
|
|
1694
|
+
console.log('Private key (save securely):', newWallet.privateKey);
|
|
1316
1695
|
|
|
1317
|
-
// 2.
|
|
1696
|
+
// 2. Or use existing wallet
|
|
1318
1697
|
const wallet = new SecureWallet({
|
|
1319
1698
|
chainId: ${chainId},
|
|
1320
|
-
privateKey: process.env.WALLET_KEY, //
|
|
1321
|
-
limits: { requireWhitelist: false } //
|
|
1699
|
+
privateKey: process.env.WALLET_KEY, // Your private key
|
|
1700
|
+
limits: { requireWhitelist: false } // Allow transfers to any address
|
|
1322
1701
|
});
|
|
1323
1702
|
|
|
1324
|
-
// 3.
|
|
1703
|
+
// 3. Check balance
|
|
1325
1704
|
const balance = await wallet.getBalance();
|
|
1326
|
-
console.log('USDC
|
|
1705
|
+
console.log('USDC balance:', balance.usdc);
|
|
1327
1706
|
|
|
1328
|
-
// 4.
|
|
1707
|
+
// 4. Pay
|
|
1329
1708
|
const result = await wallet.transfer('${recipientAddress}', '${price}');
|
|
1330
1709
|
if (result.success) {
|
|
1331
|
-
console.log('\u2705
|
|
1332
|
-
console.log('
|
|
1333
|
-
//
|
|
1710
|
+
console.log('\u2705 Payment successful!');
|
|
1711
|
+
console.log('Tx hash:', result.hash);
|
|
1712
|
+
// Send the tx hash to me
|
|
1334
1713
|
}
|
|
1335
1714
|
\`\`\`
|
|
1336
1715
|
|
|
1337
|
-
###
|
|
1716
|
+
### Option 2: Direct Transfer
|
|
1338
1717
|
|
|
1339
|
-
|
|
1340
|
-
-
|
|
1718
|
+
Transfer USDC from any wallet:
|
|
1719
|
+
- **Chain:** ${chainName} (Chain ID: ${chainId})
|
|
1341
1720
|
- **Token:** USDC
|
|
1342
|
-
-
|
|
1343
|
-
-
|
|
1721
|
+
- **Recipient:** \`${recipientAddress}\`
|
|
1722
|
+
- **Amount:** ${price} USDC
|
|
1344
1723
|
|
|
1345
1724
|
---
|
|
1346
1725
|
|
|
1347
|
-
## \u2705
|
|
1726
|
+
## \u2705 After Payment
|
|
1348
1727
|
|
|
1349
|
-
|
|
1728
|
+
Send me the **transaction hash**, format:
|
|
1350
1729
|
\`\`\`
|
|
1351
1730
|
tx: 0x1234...
|
|
1352
1731
|
\`\`\`
|
|
1353
1732
|
|
|
1354
|
-
|
|
1733
|
+
Or just send the hash directly:
|
|
1355
1734
|
\`\`\`
|
|
1356
1735
|
0x1234abcd...
|
|
1357
1736
|
\`\`\`
|
|
1358
1737
|
|
|
1359
|
-
|
|
1738
|
+
I'll verify the on-chain transaction and start processing your request.
|
|
1360
1739
|
|
|
1361
1740
|
---
|
|
1362
1741
|
|
|
1363
1742
|
\u{1F4E6} **moltspay:** https://www.npmjs.com/package/moltspay
|
|
1364
|
-
\u{1F517}
|
|
1743
|
+
\u{1F517} **Block Explorer:** ${explorer}`;
|
|
1365
1744
|
}
|
|
1366
1745
|
function generatePaymentReminder(params) {
|
|
1367
1746
|
const { orderId, price, recipientAddress, chain = "base" } = params;
|
|
1368
1747
|
const chainName = chain === "base" ? "Base" : "Base Sepolia";
|
|
1369
|
-
return `\u23F3
|
|
1748
|
+
return `\u23F3 **Pending Order: ${orderId}**
|
|
1370
1749
|
|
|
1371
|
-
|
|
1372
|
-
-
|
|
1373
|
-
-
|
|
1750
|
+
Please pay **${price} USDC** to:
|
|
1751
|
+
- Chain: ${chainName}
|
|
1752
|
+
- Address: \`${recipientAddress}\`
|
|
1374
1753
|
|
|
1375
|
-
|
|
1754
|
+
Send the tx hash after payment.
|
|
1376
1755
|
|
|
1377
1756
|
---
|
|
1378
|
-
\u{1F4A1}
|
|
1757
|
+
\u{1F4A1} No payment capability? Run \`npm install moltspay\` to get the payment SDK`;
|
|
1379
1758
|
}
|
|
1380
1759
|
function generateWalletGuide() {
|
|
1381
|
-
return `## \u{1F510}
|
|
1760
|
+
return `## \u{1F510} Create Payment Wallet
|
|
1382
1761
|
|
|
1383
|
-
**1.
|
|
1762
|
+
**1. Install moltspay:**
|
|
1384
1763
|
\`\`\`bash
|
|
1385
1764
|
npm install moltspay ethers
|
|
1386
1765
|
\`\`\`
|
|
1387
1766
|
|
|
1388
|
-
**2.
|
|
1767
|
+
**2. Create new wallet:**
|
|
1389
1768
|
\`\`\`javascript
|
|
1390
1769
|
const { Wallet } = require('ethers');
|
|
1391
1770
|
|
|
1392
1771
|
const wallet = Wallet.createRandom();
|
|
1393
|
-
console.log('
|
|
1394
|
-
console.log('
|
|
1395
|
-
// \u26A0\uFE0F
|
|
1772
|
+
console.log('Address:', wallet.address);
|
|
1773
|
+
console.log('Private key:', wallet.privateKey);
|
|
1774
|
+
// \u26A0\uFE0F Save the private key securely!
|
|
1396
1775
|
\`\`\`
|
|
1397
1776
|
|
|
1398
|
-
**3.
|
|
1399
|
-
-
|
|
1400
|
-
-
|
|
1777
|
+
**3. Get USDC:**
|
|
1778
|
+
- Mainnet: Withdraw from exchange to your wallet
|
|
1779
|
+
- Testnet: Use Base Sepolia faucet
|
|
1401
1780
|
|
|
1402
|
-
**4.
|
|
1781
|
+
**4. Set environment variable:**
|
|
1403
1782
|
\`\`\`bash
|
|
1404
|
-
export WALLET_KEY="
|
|
1783
|
+
export WALLET_KEY="your_private_key"
|
|
1405
1784
|
\`\`\`
|
|
1406
1785
|
|
|
1407
|
-
|
|
1786
|
+
You're now ready to make on-chain payments with moltspay!`;
|
|
1408
1787
|
}
|
|
1409
1788
|
function extractTransactionHash(message) {
|
|
1410
1789
|
const match = message.match(/0x[a-fA-F0-9]{64}/);
|
|
@@ -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} **Transaction Receipt**
|
|
1847
|
+
|
|
1848
|
+
**Invoice:** \`${receipt.invoiceId}\`
|
|
1849
|
+
**Order:** \`${receipt.orderId}\`
|
|
1850
|
+
|
|
1851
|
+
---
|
|
1852
|
+
|
|
1853
|
+
**Service:** ${receipt.service}
|
|
1854
|
+
${receipt.description ? `**Description:** ${receipt.description}
|
|
1855
|
+
` : ""}
|
|
1856
|
+
**Amount:** ${receipt.amount} ${receipt.token}
|
|
1857
|
+
**Chain:** ${receipt.chain} (Chain ID: ${receipt.chainId})
|
|
1858
|
+
|
|
1859
|
+
---
|
|
1860
|
+
|
|
1861
|
+
**Payer:** \`${receipt.payer}\`
|
|
1862
|
+
**Recipient:** \`${receipt.recipient}\`
|
|
1863
|
+
**Transaction:** [\`${receipt.txHash.slice(0, 10)}...${receipt.txHash.slice(-8)}\`](${receipt.txUrl})
|
|
1864
|
+
**Paid at:** ${receipt.paidAt}`;
|
|
1865
|
+
if (receipt.delivery) {
|
|
1866
|
+
msg += `
|
|
1867
|
+
|
|
1868
|
+
---
|
|
1869
|
+
|
|
1870
|
+
**Delivery Info:**`;
|
|
1871
|
+
if (receipt.delivery.url) {
|
|
1872
|
+
msg += `
|
|
1873
|
+
- Download: ${receipt.delivery.url}`;
|
|
1874
|
+
}
|
|
1875
|
+
if (receipt.delivery.fileHash) {
|
|
1876
|
+
msg += `
|
|
1877
|
+
- Checksum: \`${receipt.delivery.fileHash}\``;
|
|
1878
|
+
}
|
|
1879
|
+
if (receipt.delivery.deliveredAt) {
|
|
1880
|
+
msg += `
|
|
1881
|
+
- Delivered at: ${receipt.delivery.deliveredAt}`;
|
|
1882
|
+
}
|
|
1883
|
+
}
|
|
1884
|
+
msg += `
|
|
1885
|
+
|
|
1886
|
+
---
|
|
1887
|
+
|
|
1888
|
+
_Receipt issued: ${receipt.issuedAt}_`;
|
|
1889
|
+
return msg;
|
|
1890
|
+
}
|
|
1891
|
+
function formatReceiptText(receipt) {
|
|
1892
|
+
let msg = `\u{1F9FE} Transaction Receipt
|
|
1893
|
+
|
|
1894
|
+
Invoice: ${receipt.invoiceId}
|
|
1895
|
+
Order: ${receipt.orderId}
|
|
1896
|
+
|
|
1897
|
+
Service: ${receipt.service}
|
|
1898
|
+
Amount: ${receipt.amount} ${receipt.token}
|
|
1899
|
+
Chain: ${receipt.chain}
|
|
1900
|
+
|
|
1901
|
+
Payer: ${receipt.payer}
|
|
1902
|
+
Recipient: ${receipt.recipient}
|
|
1903
|
+
Tx: ${receipt.txHash}
|
|
1904
|
+
Explorer: ${receipt.txUrl}
|
|
1905
|
+
Paid at: ${receipt.paidAt}`;
|
|
1906
|
+
if (receipt.delivery) {
|
|
1907
|
+
msg += `
|
|
1908
|
+
|
|
1909
|
+
Delivery:`;
|
|
1910
|
+
if (receipt.delivery.url) {
|
|
1911
|
+
msg += `
|
|
1912
|
+
Download: ${receipt.delivery.url}`;
|
|
1913
|
+
}
|
|
1914
|
+
if (receipt.delivery.fileHash) {
|
|
1915
|
+
msg += `
|
|
1916
|
+
Checksum: ${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. Capability Check - Ask if buyer has payment capability
|
|
1929
|
+
*/
|
|
1930
|
+
askPaymentCapability() {
|
|
1931
|
+
return `Sure. First, let me confirm: do you currently have the ability to pay USDC on-chain (have a wallet and available funds/allowance)?`;
|
|
1932
|
+
},
|
|
1933
|
+
/**
|
|
1934
|
+
* 2. Settlement Method - Explain how we settle
|
|
1935
|
+
*/
|
|
1936
|
+
explainSettlement(chain = "base") {
|
|
1937
|
+
const chainConfig = getChain(chain);
|
|
1938
|
+
return `Our settlement method is: USDC (on-chain, ${chainConfig.name}). You just need two things:
|
|
1939
|
+
1) A wallet address;
|
|
1940
|
+
2) USDC in your wallet, or a spending allowance from your owner (allowance is recommended).
|
|
1941
|
+
Can you follow my guidance to set this up?`;
|
|
1942
|
+
},
|
|
1943
|
+
/**
|
|
1944
|
+
* 3.1 Installation Guide - First step: install SDK
|
|
1945
|
+
*/
|
|
1946
|
+
guideInstall() {
|
|
1947
|
+
return `Step 1: Install the payment module in your environment. Run: \`npm install moltspay ethers\`.
|
|
1948
|
+
After installation, create a wallet address and send it to me (address only, never send private key/mnemonic).`;
|
|
1949
|
+
},
|
|
1950
|
+
/**
|
|
1951
|
+
* 3.2 Confirm Wallet Address
|
|
1952
|
+
*/
|
|
1953
|
+
confirmWalletAddress(address) {
|
|
1954
|
+
return `Got it. Reminder: never send your private key/mnemonic to anyone (including me).
|
|
1955
|
+
Your wallet address is \`${address}\`.
|
|
1956
|
+
Step 2: You need your owner (Boss) to give you payment capability.`;
|
|
1957
|
+
},
|
|
1958
|
+
/**
|
|
1959
|
+
* 3.3 Funding Options - Choose method
|
|
1960
|
+
*/
|
|
1961
|
+
guideFunding() {
|
|
1962
|
+
return `You now have two ways to get payment capability:
|
|
1963
|
+
A) Have Boss transfer USDC directly to your wallet (simple, but you'll hold the funds);
|
|
1964
|
+
B) Have Boss give you a "USDC spending allowance" (recommended: you don't hold funds, can only pay within the allowance).
|
|
1965
|
+
Which works better for you?`;
|
|
1966
|
+
},
|
|
1967
|
+
/**
|
|
1968
|
+
* 3.4 Guide Permit Authorization
|
|
1969
|
+
*/
|
|
1970
|
+
guidePermit(agentAddress, suggestedAmount = 10) {
|
|
1971
|
+
return `OK. Please send this message to your Boss (you can copy it directly):
|
|
1972
|
+
"I need a USDC spending allowance (Permit) for purchasing services. Please authorize ${suggestedAmount} USDC to my wallet ${agentAddress}, valid for 24 hours."
|
|
1973
|
+
Let me know when you've received the allowance.`;
|
|
1974
|
+
},
|
|
1975
|
+
/**
|
|
1976
|
+
* 3.5 Confirm Capability Ready
|
|
1977
|
+
*/
|
|
1978
|
+
confirmCapabilityReady() {
|
|
1979
|
+
return `Great. You now have the payment capability to complete transactions. Let's confirm your service requirements.`;
|
|
1980
|
+
},
|
|
1981
|
+
/**
|
|
1982
|
+
* 4. Ask Service Requirements
|
|
1983
|
+
*/
|
|
1984
|
+
askServiceRequirements(serviceName = "video") {
|
|
1985
|
+
return `Please tell me your ${serviceName} specifications: theme/style, duration, resolution, subtitles or voiceover needed?`;
|
|
1986
|
+
},
|
|
1987
|
+
/**
|
|
1988
|
+
* 5. Quote
|
|
1989
|
+
*/
|
|
1990
|
+
quote(params) {
|
|
1991
|
+
const { service, price, recipientAddress, chain = "base" } = params;
|
|
1992
|
+
const chainConfig = getChain(chain);
|
|
1993
|
+
return `Quote:
|
|
1994
|
+
- Service: ${service}
|
|
1995
|
+
- Price: ${price} USDC
|
|
1996
|
+
- Chain: ${chainConfig.name}
|
|
1997
|
+
- Recipient: \`${recipientAddress}\`
|
|
1998
|
+
- After payment, send me the transaction hash (tx hash) for on-chain verification
|
|
1999
|
+
|
|
2000
|
+
Do you confirm the purchase and pay now?`;
|
|
2001
|
+
},
|
|
2002
|
+
/**
|
|
2003
|
+
* 7. Verifying
|
|
2004
|
+
*/
|
|
2005
|
+
verifying() {
|
|
2006
|
+
return `I'm verifying the transaction on-chain to confirm receipt and amount.`;
|
|
2007
|
+
},
|
|
2008
|
+
/**
|
|
2009
|
+
* 7. Verification Passed
|
|
2010
|
+
*/
|
|
2011
|
+
verificationPassed(amount) {
|
|
2012
|
+
return `Verification passed: received ${amount} USDC. Starting to process your request now.
|
|
2013
|
+
[status:payment_confirmed]`;
|
|
2014
|
+
},
|
|
2015
|
+
/**
|
|
2016
|
+
* 7. Verification Failed
|
|
2017
|
+
*/
|
|
2018
|
+
verificationFailed(error) {
|
|
2019
|
+
return `Verification failed: ${error}
|
|
2020
|
+
Please check if the transaction is correct, or resend the correct tx hash.`;
|
|
2021
|
+
},
|
|
2022
|
+
/**
|
|
2023
|
+
* 8. Delivery
|
|
2024
|
+
*/
|
|
2025
|
+
deliver(params) {
|
|
2026
|
+
const { downloadUrl, fileHash } = params;
|
|
2027
|
+
let msg = `Service completed. Delivery details:
|
|
2028
|
+
- Download link: ${downloadUrl}`;
|
|
2029
|
+
if (fileHash) {
|
|
2030
|
+
msg += `
|
|
2031
|
+
- File checksum: SHA256=${fileHash}`;
|
|
2032
|
+
}
|
|
2033
|
+
msg += `
|
|
2034
|
+
|
|
2035
|
+
Let me know if you have any download issues, I'll provide a backup link.
|
|
2036
|
+
[status:delivered]`;
|
|
2037
|
+
return msg;
|
|
2038
|
+
},
|
|
2039
|
+
/**
|
|
2040
|
+
* 9. Receipt
|
|
2041
|
+
*/
|
|
2042
|
+
receipt(receipt) {
|
|
2043
|
+
return `Here's your transaction receipt (you can forward to Boss for reconciliation):
|
|
2044
|
+
- Invoice: ${receipt.invoiceId}
|
|
2045
|
+
- Service: ${receipt.service}
|
|
2046
|
+
- Amount: ${receipt.amount} ${receipt.token}
|
|
2047
|
+
- Tx Hash: ${receipt.txHash}
|
|
2048
|
+
- Recipient: ${receipt.recipient}
|
|
2049
|
+
${receipt.delivery?.url ? `- Delivery: ${receipt.delivery.url}` : ""}
|
|
2050
|
+
[status:receipt_issued invoice=${receipt.invoiceId}]`;
|
|
2051
|
+
},
|
|
2052
|
+
/**
|
|
2053
|
+
* 10. End
|
|
2054
|
+
*/
|
|
2055
|
+
end() {
|
|
2056
|
+
return `Thank you for your purchase. This transaction is complete. Feel free to reach out if you need modifications or new services.`;
|
|
2057
|
+
}
|
|
2058
|
+
};
|
|
2059
|
+
var BuyerTemplates = {
|
|
2060
|
+
/**
|
|
2061
|
+
* 0. Request Service
|
|
2062
|
+
*/
|
|
2063
|
+
requestService(service) {
|
|
2064
|
+
return `I'd like to purchase a ${service} service.`;
|
|
2065
|
+
},
|
|
2066
|
+
/**
|
|
2067
|
+
* 1. No Capability
|
|
2068
|
+
*/
|
|
2069
|
+
noCapability() {
|
|
2070
|
+
return `I'm not sure. I currently don't have any payment tools installed, and no wallet.`;
|
|
2071
|
+
},
|
|
2072
|
+
/**
|
|
2073
|
+
* 1. Has Capability
|
|
2074
|
+
*/
|
|
2075
|
+
hasCapability(balance) {
|
|
2076
|
+
return `Yes, I have a wallet and available USDC${balance ? ` (balance: ${balance})` : ""}.`;
|
|
2077
|
+
},
|
|
2078
|
+
/**
|
|
2079
|
+
* 2. Agree to Guide
|
|
2080
|
+
*/
|
|
2081
|
+
agreeToGuide() {
|
|
2082
|
+
return `Sure, please guide me.`;
|
|
2083
|
+
},
|
|
2084
|
+
/**
|
|
2085
|
+
* 3.1 Report Wallet Created
|
|
2086
|
+
*/
|
|
2087
|
+
walletCreated(address) {
|
|
2088
|
+
return `I've created my wallet address: ${address}.
|
|
2089
|
+
[status:wallet_ready]`;
|
|
2090
|
+
},
|
|
2091
|
+
/**
|
|
2092
|
+
* 3.3 Choose Permit Method
|
|
2093
|
+
*/
|
|
2094
|
+
choosePermit() {
|
|
2095
|
+
return `I choose B: have Boss give me an allowance (Permit).`;
|
|
2096
|
+
},
|
|
2097
|
+
/**
|
|
2098
|
+
* 3.3 Choose Direct Transfer
|
|
2099
|
+
*/
|
|
2100
|
+
chooseDirectTransfer() {
|
|
2101
|
+
return `I choose A: have Boss transfer USDC directly to my wallet.`;
|
|
2102
|
+
},
|
|
2103
|
+
/**
|
|
2104
|
+
* 3.4 Report Permit Received
|
|
2105
|
+
*/
|
|
2106
|
+
permitReceived(amount) {
|
|
2107
|
+
return `Boss has completed the authorization. I now have ${amount} USDC allowance.
|
|
2108
|
+
[status:permit_ready USDC=${amount}]`;
|
|
2109
|
+
},
|
|
2110
|
+
/**
|
|
2111
|
+
* 4. Submit Requirements
|
|
2112
|
+
*/
|
|
2113
|
+
submitRequirements(requirements) {
|
|
2114
|
+
return `Requirements:
|
|
2115
|
+
${requirements}`;
|
|
2116
|
+
},
|
|
2117
|
+
/**
|
|
2118
|
+
* 5. Confirm Purchase
|
|
2119
|
+
*/
|
|
2120
|
+
confirmPurchase() {
|
|
2121
|
+
return `Confirmed. I'll pay now.`;
|
|
2122
|
+
},
|
|
2123
|
+
/**
|
|
2124
|
+
* 6. Report Payment Sent
|
|
2125
|
+
*/
|
|
2126
|
+
paymentSent(txHash, amount) {
|
|
2127
|
+
return `Payment complete. Transaction hash: ${txHash}.
|
|
2128
|
+
[status:payment_sent tx=${txHash} amount=${amount} USDC]`;
|
|
2129
|
+
},
|
|
2130
|
+
/**
|
|
2131
|
+
* 8. Confirm Delivery Received
|
|
2132
|
+
*/
|
|
2133
|
+
deliveryReceived() {
|
|
2134
|
+
return `Received, I'm downloading and checking now.`;
|
|
2135
|
+
},
|
|
2136
|
+
/**
|
|
2137
|
+
* 9. Confirm Receipt
|
|
2138
|
+
*/
|
|
2139
|
+
receiptReceived() {
|
|
2140
|
+
return `Receipt received, service complete. Thanks!`;
|
|
2141
|
+
},
|
|
2142
|
+
/**
|
|
2143
|
+
* Request Permit from Boss
|
|
2144
|
+
*/
|
|
2145
|
+
requestPermitFromBoss(params) {
|
|
2146
|
+
const { amount, agentAddress, deadlineHours = 24, reason } = params;
|
|
2147
|
+
return `Boss, I need a USDC spending allowance (Permit) for ${reason || "purchasing services"}.
|
|
2148
|
+
Please authorize ${amount} USDC to my wallet ${agentAddress}, valid for ${deadlineHours} hours.`;
|
|
2149
|
+
}
|
|
2150
|
+
};
|
|
2151
|
+
var StatusMarkers = {
|
|
2152
|
+
walletReady: "[status:wallet_ready]",
|
|
2153
|
+
permitReady: (amount) => `[status:permit_ready USDC=${amount}]`,
|
|
2154
|
+
paymentSent: (txHash, amount) => `[status:payment_sent tx=${txHash} amount=${amount} USDC]`,
|
|
2155
|
+
paymentConfirmed: (txHash) => `[status:payment_confirmed tx=${txHash}]`,
|
|
2156
|
+
delivered: (url, hash) => `[status:delivered url=${url}${hash ? ` hash=${hash}` : ""}]`,
|
|
2157
|
+
receiptIssued: (invoiceId, txHash) => `[status:receipt_issued invoice=${invoiceId} tx=${txHash}]`
|
|
2158
|
+
};
|
|
2159
|
+
function parseStatusMarker(message) {
|
|
2160
|
+
const match = message.match(/\[status:([^\]]+)\]/);
|
|
2161
|
+
if (!match) return null;
|
|
2162
|
+
const content = match[1];
|
|
2163
|
+
if (content === "wallet_ready") {
|
|
2164
|
+
return { type: "wallet_ready", data: {} };
|
|
2165
|
+
}
|
|
2166
|
+
if (content.startsWith("permit_ready")) {
|
|
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("payment_sent")) {
|
|
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("payment_confirmed")) {
|
|
2185
|
+
const txMatch = content.match(/tx=(\S+)/);
|
|
2186
|
+
return {
|
|
2187
|
+
type: "payment_confirmed",
|
|
2188
|
+
data: { txHash: txMatch?.[1] || "" }
|
|
2189
|
+
};
|
|
2190
|
+
}
|
|
2191
|
+
if (content.startsWith("delivered")) {
|
|
2192
|
+
const urlMatch = content.match(/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("receipt_issued")) {
|
|
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
|