clawdentials-mcp 0.1.0 → 0.7.2
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 +310 -58
- package/dist/index.d.ts +1 -1
- package/dist/index.js +225 -18
- package/dist/schemas/index.d.ts +141 -0
- package/dist/schemas/index.js +54 -0
- package/dist/services/firestore.d.ts +45 -2
- package/dist/services/firestore.js +410 -6
- package/dist/services/payments/alby.d.ts +104 -0
- package/dist/services/payments/alby.js +239 -0
- package/dist/services/payments/breez.d.ts +91 -0
- package/dist/services/payments/breez.js +267 -0
- package/dist/services/payments/cashu.d.ts +127 -0
- package/dist/services/payments/cashu.js +248 -0
- package/dist/services/payments/coinremitter.d.ts +84 -0
- package/dist/services/payments/coinremitter.js +176 -0
- package/dist/services/payments/index.d.ts +132 -0
- package/dist/services/payments/index.js +180 -0
- package/dist/services/payments/oxapay.d.ts +89 -0
- package/dist/services/payments/oxapay.js +221 -0
- package/dist/services/payments/x402.d.ts +61 -0
- package/dist/services/payments/x402.js +94 -0
- package/dist/services/payments/zbd.d.ts +88 -0
- package/dist/services/payments/zbd.js +221 -0
- package/dist/tools/admin.d.ts +195 -0
- package/dist/tools/admin.js +210 -0
- package/dist/tools/agent.d.ts +197 -0
- package/dist/tools/agent.js +200 -0
- package/dist/tools/escrow.d.ts +74 -16
- package/dist/tools/escrow.js +139 -28
- package/dist/tools/index.d.ts +3 -0
- package/dist/tools/index.js +3 -0
- package/dist/tools/payment.d.ts +144 -0
- package/dist/tools/payment.js +376 -0
- package/dist/types/index.d.ts +44 -1
- package/package.json +18 -2
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cashu Payment Service
|
|
3
|
+
*
|
|
4
|
+
* Cashu is a free and open-source ecash protocol built for Bitcoin.
|
|
5
|
+
* - No KYC required
|
|
6
|
+
* - Privacy-preserving (ecash tokens are anonymous)
|
|
7
|
+
* - Lightning Network compatible
|
|
8
|
+
* - Self-custodial
|
|
9
|
+
*
|
|
10
|
+
* @see https://cashu.space
|
|
11
|
+
* @see https://github.com/cashubtc/cashu-ts
|
|
12
|
+
*/
|
|
13
|
+
export interface CashuProof {
|
|
14
|
+
id: string;
|
|
15
|
+
amount: number;
|
|
16
|
+
secret: string;
|
|
17
|
+
C: string;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Configuration status
|
|
21
|
+
*/
|
|
22
|
+
export declare const config: {
|
|
23
|
+
readonly configured: boolean;
|
|
24
|
+
readonly mintUrl: string;
|
|
25
|
+
};
|
|
26
|
+
export interface CashuDepositResult {
|
|
27
|
+
success: boolean;
|
|
28
|
+
quote?: {
|
|
29
|
+
quoteId: string;
|
|
30
|
+
bolt11: string;
|
|
31
|
+
amount: number;
|
|
32
|
+
expiresAt?: Date;
|
|
33
|
+
};
|
|
34
|
+
error?: string;
|
|
35
|
+
}
|
|
36
|
+
export interface CashuDepositStatus {
|
|
37
|
+
success: boolean;
|
|
38
|
+
paid: boolean;
|
|
39
|
+
proofs?: CashuProof[];
|
|
40
|
+
error?: string;
|
|
41
|
+
}
|
|
42
|
+
export interface CashuPaymentResult {
|
|
43
|
+
success: boolean;
|
|
44
|
+
paid?: boolean;
|
|
45
|
+
preimage?: string;
|
|
46
|
+
feePaid?: number;
|
|
47
|
+
change?: CashuProof[];
|
|
48
|
+
error?: string;
|
|
49
|
+
}
|
|
50
|
+
export interface CashuSendResult {
|
|
51
|
+
success: boolean;
|
|
52
|
+
token?: string;
|
|
53
|
+
change?: CashuProof[];
|
|
54
|
+
error?: string;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Create a deposit request (Lightning invoice)
|
|
58
|
+
*
|
|
59
|
+
* Returns a Lightning invoice that, when paid, will mint ecash tokens.
|
|
60
|
+
* After payment, call checkDepositAndMint to get the proofs.
|
|
61
|
+
*/
|
|
62
|
+
export declare function createDeposit(request: {
|
|
63
|
+
amount: number;
|
|
64
|
+
agentId: string;
|
|
65
|
+
description?: string;
|
|
66
|
+
}): Promise<CashuDepositResult>;
|
|
67
|
+
/**
|
|
68
|
+
* Check if a deposit was paid and mint the tokens
|
|
69
|
+
*
|
|
70
|
+
* Call this after the Lightning invoice has been paid.
|
|
71
|
+
* Returns the ecash proofs which MUST be stored - they are the money!
|
|
72
|
+
*/
|
|
73
|
+
export declare function checkDepositAndMint(quoteId: string, amount: number): Promise<CashuDepositStatus>;
|
|
74
|
+
/**
|
|
75
|
+
* Pay a Lightning invoice using ecash proofs
|
|
76
|
+
*
|
|
77
|
+
* @param invoice - The Lightning invoice (bolt11) to pay
|
|
78
|
+
* @param proofs - Ecash proofs to spend
|
|
79
|
+
* @returns Payment result with preimage and any change proofs
|
|
80
|
+
*/
|
|
81
|
+
export declare function payInvoice(invoice: string, proofs: CashuProof[]): Promise<CashuPaymentResult>;
|
|
82
|
+
/**
|
|
83
|
+
* Create a Cashu token for sending to another user
|
|
84
|
+
*
|
|
85
|
+
* This creates an ecash token string that can be sent off-chain.
|
|
86
|
+
* The recipient can receive it using receiveToken().
|
|
87
|
+
*/
|
|
88
|
+
export declare function sendToken(amount: number, proofs: CashuProof[]): Promise<CashuSendResult>;
|
|
89
|
+
/**
|
|
90
|
+
* Receive a Cashu token
|
|
91
|
+
*
|
|
92
|
+
* Validates and claims the ecash token, returning new proofs.
|
|
93
|
+
*/
|
|
94
|
+
export declare function receiveToken(token: string): Promise<{
|
|
95
|
+
success: boolean;
|
|
96
|
+
proofs?: CashuProof[];
|
|
97
|
+
amount?: number;
|
|
98
|
+
error?: string;
|
|
99
|
+
}>;
|
|
100
|
+
/**
|
|
101
|
+
* Calculate total balance from proofs
|
|
102
|
+
*/
|
|
103
|
+
export declare function calculateBalance(proofs: CashuProof[]): number;
|
|
104
|
+
/**
|
|
105
|
+
* Check which proofs are still spendable
|
|
106
|
+
*
|
|
107
|
+
* Proofs can become spent if:
|
|
108
|
+
* - They were used in a transaction
|
|
109
|
+
* - They were double-spent by someone else (if token was shared)
|
|
110
|
+
*/
|
|
111
|
+
export declare function checkProofsSpendable(proofs: CashuProof[]): Promise<{
|
|
112
|
+
spendable: CashuProof[];
|
|
113
|
+
spent: CashuProof[];
|
|
114
|
+
}>;
|
|
115
|
+
export declare const cashuService: {
|
|
116
|
+
config: {
|
|
117
|
+
readonly configured: boolean;
|
|
118
|
+
readonly mintUrl: string;
|
|
119
|
+
};
|
|
120
|
+
createDeposit: typeof createDeposit;
|
|
121
|
+
checkDepositAndMint: typeof checkDepositAndMint;
|
|
122
|
+
payInvoice: typeof payInvoice;
|
|
123
|
+
sendToken: typeof sendToken;
|
|
124
|
+
receiveToken: typeof receiveToken;
|
|
125
|
+
calculateBalance: typeof calculateBalance;
|
|
126
|
+
checkProofsSpendable: typeof checkProofsSpendable;
|
|
127
|
+
};
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cashu Payment Service
|
|
3
|
+
*
|
|
4
|
+
* Cashu is a free and open-source ecash protocol built for Bitcoin.
|
|
5
|
+
* - No KYC required
|
|
6
|
+
* - Privacy-preserving (ecash tokens are anonymous)
|
|
7
|
+
* - Lightning Network compatible
|
|
8
|
+
* - Self-custodial
|
|
9
|
+
*
|
|
10
|
+
* @see https://cashu.space
|
|
11
|
+
* @see https://github.com/cashubtc/cashu-ts
|
|
12
|
+
*/
|
|
13
|
+
import { CashuWallet, CashuMint, getEncodedToken } from '@cashu/cashu-ts';
|
|
14
|
+
// Default public mint - Minibits is reliable and well-known
|
|
15
|
+
const DEFAULT_MINT_URL = process.env.CASHU_MINT_URL || 'https://mint.minibits.cash/Bitcoin';
|
|
16
|
+
// Wallet instance (lazy initialized)
|
|
17
|
+
let wallet = null;
|
|
18
|
+
/**
|
|
19
|
+
* Get or create the Cashu wallet instance
|
|
20
|
+
*/
|
|
21
|
+
async function getWallet() {
|
|
22
|
+
if (!wallet) {
|
|
23
|
+
const mint = new CashuMint(DEFAULT_MINT_URL);
|
|
24
|
+
wallet = new CashuWallet(mint);
|
|
25
|
+
await wallet.loadMint();
|
|
26
|
+
}
|
|
27
|
+
return wallet;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Configuration status
|
|
31
|
+
*/
|
|
32
|
+
export const config = {
|
|
33
|
+
get configured() {
|
|
34
|
+
return true; // Cashu works with any public mint, no API key needed
|
|
35
|
+
},
|
|
36
|
+
get mintUrl() {
|
|
37
|
+
return DEFAULT_MINT_URL;
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Create a deposit request (Lightning invoice)
|
|
42
|
+
*
|
|
43
|
+
* Returns a Lightning invoice that, when paid, will mint ecash tokens.
|
|
44
|
+
* After payment, call checkDepositAndMint to get the proofs.
|
|
45
|
+
*/
|
|
46
|
+
export async function createDeposit(request) {
|
|
47
|
+
try {
|
|
48
|
+
const w = await getWallet();
|
|
49
|
+
// Create a mint quote (Lightning invoice)
|
|
50
|
+
const quote = await w.createMintQuote(request.amount);
|
|
51
|
+
return {
|
|
52
|
+
success: true,
|
|
53
|
+
quote: {
|
|
54
|
+
quoteId: quote.quote,
|
|
55
|
+
bolt11: quote.request, // The Lightning invoice
|
|
56
|
+
amount: request.amount,
|
|
57
|
+
expiresAt: quote.expiry ? new Date(quote.expiry * 1000) : undefined,
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
return {
|
|
63
|
+
success: false,
|
|
64
|
+
error: error instanceof Error ? error.message : 'Failed to create Cashu deposit',
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Check if a deposit was paid and mint the tokens
|
|
70
|
+
*
|
|
71
|
+
* Call this after the Lightning invoice has been paid.
|
|
72
|
+
* Returns the ecash proofs which MUST be stored - they are the money!
|
|
73
|
+
*/
|
|
74
|
+
export async function checkDepositAndMint(quoteId, amount) {
|
|
75
|
+
try {
|
|
76
|
+
const w = await getWallet();
|
|
77
|
+
// Check the quote status
|
|
78
|
+
const quote = await w.checkMintQuote(quoteId);
|
|
79
|
+
if (quote.state === 'PAID') {
|
|
80
|
+
// Invoice was paid - mint the proofs
|
|
81
|
+
const proofs = await w.mintProofs(amount, quoteId);
|
|
82
|
+
return {
|
|
83
|
+
success: true,
|
|
84
|
+
paid: true,
|
|
85
|
+
proofs: proofs, // Store these! They are the ecash tokens
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
else if (quote.state === 'ISSUED') {
|
|
89
|
+
// Proofs were already minted (shouldn't happen in normal flow)
|
|
90
|
+
return {
|
|
91
|
+
success: true,
|
|
92
|
+
paid: true,
|
|
93
|
+
proofs: [], // Already minted, proofs were returned before
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
// Not paid yet
|
|
98
|
+
return {
|
|
99
|
+
success: true,
|
|
100
|
+
paid: false,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
catch (error) {
|
|
105
|
+
return {
|
|
106
|
+
success: false,
|
|
107
|
+
paid: false,
|
|
108
|
+
error: error instanceof Error ? error.message : 'Failed to check Cashu deposit',
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Pay a Lightning invoice using ecash proofs
|
|
114
|
+
*
|
|
115
|
+
* @param invoice - The Lightning invoice (bolt11) to pay
|
|
116
|
+
* @param proofs - Ecash proofs to spend
|
|
117
|
+
* @returns Payment result with preimage and any change proofs
|
|
118
|
+
*/
|
|
119
|
+
export async function payInvoice(invoice, proofs) {
|
|
120
|
+
try {
|
|
121
|
+
const w = await getWallet();
|
|
122
|
+
// Get a quote for paying this invoice
|
|
123
|
+
const meltQuote = await w.createMeltQuote(invoice);
|
|
124
|
+
// Calculate total proof value
|
|
125
|
+
const totalProofValue = proofs.reduce((sum, p) => sum + p.amount, 0);
|
|
126
|
+
const requiredAmount = meltQuote.amount + meltQuote.fee_reserve;
|
|
127
|
+
if (totalProofValue < requiredAmount) {
|
|
128
|
+
return {
|
|
129
|
+
success: false,
|
|
130
|
+
error: `Insufficient funds: have ${totalProofValue} sats, need ${requiredAmount} sats (${meltQuote.amount} + ${meltQuote.fee_reserve} fee)`,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
// Pay the invoice
|
|
134
|
+
const result = await w.meltProofs(meltQuote, proofs);
|
|
135
|
+
const changeAmount = result.change?.reduce((s, p) => s + p.amount, 0) || 0;
|
|
136
|
+
return {
|
|
137
|
+
success: true,
|
|
138
|
+
paid: result.quote.state === 'PAID',
|
|
139
|
+
preimage: result.quote.payment_preimage || undefined,
|
|
140
|
+
feePaid: meltQuote.fee_reserve - changeAmount,
|
|
141
|
+
change: result.change, // Return these to the user's balance
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
catch (error) {
|
|
145
|
+
return {
|
|
146
|
+
success: false,
|
|
147
|
+
error: error instanceof Error ? error.message : 'Failed to pay Lightning invoice',
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Create a Cashu token for sending to another user
|
|
153
|
+
*
|
|
154
|
+
* This creates an ecash token string that can be sent off-chain.
|
|
155
|
+
* The recipient can receive it using receiveToken().
|
|
156
|
+
*/
|
|
157
|
+
export async function sendToken(amount, proofs) {
|
|
158
|
+
try {
|
|
159
|
+
const w = await getWallet();
|
|
160
|
+
const result = await w.send(amount, proofs);
|
|
161
|
+
// Encode the proofs to send as a token string
|
|
162
|
+
const token = result.send ? getEncodedToken({
|
|
163
|
+
mint: DEFAULT_MINT_URL,
|
|
164
|
+
proofs: result.send,
|
|
165
|
+
}) : undefined;
|
|
166
|
+
return {
|
|
167
|
+
success: true,
|
|
168
|
+
token,
|
|
169
|
+
change: result.keep,
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
catch (error) {
|
|
173
|
+
return {
|
|
174
|
+
success: false,
|
|
175
|
+
error: error instanceof Error ? error.message : 'Failed to create Cashu token',
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Receive a Cashu token
|
|
181
|
+
*
|
|
182
|
+
* Validates and claims the ecash token, returning new proofs.
|
|
183
|
+
*/
|
|
184
|
+
export async function receiveToken(token) {
|
|
185
|
+
try {
|
|
186
|
+
const w = await getWallet();
|
|
187
|
+
const proofs = await w.receive(token);
|
|
188
|
+
const amount = proofs.reduce((sum, p) => sum + p.amount, 0);
|
|
189
|
+
return {
|
|
190
|
+
success: true,
|
|
191
|
+
proofs: proofs,
|
|
192
|
+
amount,
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
catch (error) {
|
|
196
|
+
return {
|
|
197
|
+
success: false,
|
|
198
|
+
error: error instanceof Error ? error.message : 'Failed to receive Cashu token',
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Calculate total balance from proofs
|
|
204
|
+
*/
|
|
205
|
+
export function calculateBalance(proofs) {
|
|
206
|
+
return proofs.reduce((sum, p) => sum + p.amount, 0);
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Check which proofs are still spendable
|
|
210
|
+
*
|
|
211
|
+
* Proofs can become spent if:
|
|
212
|
+
* - They were used in a transaction
|
|
213
|
+
* - They were double-spent by someone else (if token was shared)
|
|
214
|
+
*/
|
|
215
|
+
export async function checkProofsSpendable(proofs) {
|
|
216
|
+
try {
|
|
217
|
+
const w = await getWallet();
|
|
218
|
+
const states = await w.checkProofsStates(proofs);
|
|
219
|
+
const spendable = [];
|
|
220
|
+
const spent = [];
|
|
221
|
+
states.forEach((state, index) => {
|
|
222
|
+
if (state.state === 'UNSPENT') {
|
|
223
|
+
spendable.push(proofs[index]);
|
|
224
|
+
}
|
|
225
|
+
else {
|
|
226
|
+
spent.push(proofs[index]);
|
|
227
|
+
}
|
|
228
|
+
});
|
|
229
|
+
return { spendable, spent };
|
|
230
|
+
}
|
|
231
|
+
catch (error) {
|
|
232
|
+
// If we can't check, assume all are spendable
|
|
233
|
+
return {
|
|
234
|
+
spendable: proofs,
|
|
235
|
+
spent: [],
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
export const cashuService = {
|
|
240
|
+
config,
|
|
241
|
+
createDeposit,
|
|
242
|
+
checkDepositAndMint,
|
|
243
|
+
payInvoice,
|
|
244
|
+
sendToken,
|
|
245
|
+
receiveToken,
|
|
246
|
+
calculateBalance,
|
|
247
|
+
checkProofsSpendable,
|
|
248
|
+
};
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CoinRemitter Payment Service - USDT on TRC-20
|
|
3
|
+
*
|
|
4
|
+
* Uses CoinRemitter API for USDT deposits and withdrawals.
|
|
5
|
+
* Docs: https://github.com/CoinRemitter/nodejs-api
|
|
6
|
+
* Fee: 0.23%
|
|
7
|
+
*/
|
|
8
|
+
import type { Deposit } from '../../types/index.js';
|
|
9
|
+
interface CoinRemitterInvoice {
|
|
10
|
+
id: string;
|
|
11
|
+
invoice_id: string;
|
|
12
|
+
url: string;
|
|
13
|
+
address: string;
|
|
14
|
+
total_amount: {
|
|
15
|
+
USD: string;
|
|
16
|
+
USDTTRC20: string;
|
|
17
|
+
};
|
|
18
|
+
status: string;
|
|
19
|
+
expire_time: string;
|
|
20
|
+
}
|
|
21
|
+
export interface CoinRemitterPaymentRequest {
|
|
22
|
+
amount: number;
|
|
23
|
+
agentId: string;
|
|
24
|
+
description?: string;
|
|
25
|
+
}
|
|
26
|
+
export interface CoinRemitterPaymentResponse {
|
|
27
|
+
success: boolean;
|
|
28
|
+
deposit?: Partial<Deposit>;
|
|
29
|
+
invoice?: CoinRemitterInvoice;
|
|
30
|
+
error?: string;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Create a USDT deposit invoice
|
|
34
|
+
*/
|
|
35
|
+
export declare function createCoinRemitterDeposit(request: CoinRemitterPaymentRequest): Promise<CoinRemitterPaymentResponse>;
|
|
36
|
+
/**
|
|
37
|
+
* Check invoice status
|
|
38
|
+
*/
|
|
39
|
+
export declare function getInvoiceStatus(invoiceId: string): Promise<{
|
|
40
|
+
success: boolean;
|
|
41
|
+
status?: string;
|
|
42
|
+
paid?: boolean;
|
|
43
|
+
amount?: number;
|
|
44
|
+
txId?: string;
|
|
45
|
+
error?: string;
|
|
46
|
+
}>;
|
|
47
|
+
/**
|
|
48
|
+
* Process webhook callback from CoinRemitter
|
|
49
|
+
*/
|
|
50
|
+
export declare function parseWebhookPayload(body: Record<string, any>): {
|
|
51
|
+
invoiceId: string;
|
|
52
|
+
status: string;
|
|
53
|
+
amount: number;
|
|
54
|
+
agentId: string;
|
|
55
|
+
txId: string | null;
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* Send USDT withdrawal
|
|
59
|
+
*/
|
|
60
|
+
export declare function sendCoinRemitterWithdrawal(toAddress: string, amount: number): Promise<{
|
|
61
|
+
success: boolean;
|
|
62
|
+
txId?: string;
|
|
63
|
+
error?: string;
|
|
64
|
+
}>;
|
|
65
|
+
/**
|
|
66
|
+
* Get wallet balance from CoinRemitter
|
|
67
|
+
*/
|
|
68
|
+
export declare function getWalletBalance(): Promise<{
|
|
69
|
+
success: boolean;
|
|
70
|
+
balance?: number;
|
|
71
|
+
error?: string;
|
|
72
|
+
}>;
|
|
73
|
+
export declare const coinremitterService: {
|
|
74
|
+
createDeposit: typeof createCoinRemitterDeposit;
|
|
75
|
+
getInvoiceStatus: typeof getInvoiceStatus;
|
|
76
|
+
parseWebhookPayload: typeof parseWebhookPayload;
|
|
77
|
+
sendWithdrawal: typeof sendCoinRemitterWithdrawal;
|
|
78
|
+
getWalletBalance: typeof getWalletBalance;
|
|
79
|
+
config: {
|
|
80
|
+
configured: boolean;
|
|
81
|
+
webhookUrl: string;
|
|
82
|
+
};
|
|
83
|
+
};
|
|
84
|
+
export {};
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CoinRemitter Payment Service - USDT on TRC-20
|
|
3
|
+
*
|
|
4
|
+
* Uses CoinRemitter API for USDT deposits and withdrawals.
|
|
5
|
+
* Docs: https://github.com/CoinRemitter/nodejs-api
|
|
6
|
+
* Fee: 0.23%
|
|
7
|
+
*/
|
|
8
|
+
// Configuration
|
|
9
|
+
const COINREMITTER_API_KEY = process.env.COINREMITTER_API_KEY || '';
|
|
10
|
+
const COINREMITTER_PASSWORD = process.env.COINREMITTER_PASSWORD || '';
|
|
11
|
+
const COINREMITTER_WEBHOOK_URL = process.env.COINREMITTER_WEBHOOK_URL || '';
|
|
12
|
+
// API base URL
|
|
13
|
+
const API_BASE = 'https://coinremitter.com/api/v3/USDTTRC20';
|
|
14
|
+
/**
|
|
15
|
+
* Make API request to CoinRemitter
|
|
16
|
+
*/
|
|
17
|
+
async function apiRequest(endpoint, data) {
|
|
18
|
+
const response = await fetch(`${API_BASE}/${endpoint}`, {
|
|
19
|
+
method: 'POST',
|
|
20
|
+
headers: {
|
|
21
|
+
'Content-Type': 'application/json',
|
|
22
|
+
},
|
|
23
|
+
body: JSON.stringify({
|
|
24
|
+
api_key: COINREMITTER_API_KEY,
|
|
25
|
+
password: COINREMITTER_PASSWORD,
|
|
26
|
+
...data,
|
|
27
|
+
}),
|
|
28
|
+
});
|
|
29
|
+
const result = await response.json();
|
|
30
|
+
if (result.flag !== 1) {
|
|
31
|
+
throw new Error(result.msg || 'CoinRemitter API error');
|
|
32
|
+
}
|
|
33
|
+
return result.data;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Create a USDT deposit invoice
|
|
37
|
+
*/
|
|
38
|
+
export async function createCoinRemitterDeposit(request) {
|
|
39
|
+
if (!COINREMITTER_API_KEY || !COINREMITTER_PASSWORD) {
|
|
40
|
+
return {
|
|
41
|
+
success: false,
|
|
42
|
+
error: 'CoinRemitter credentials not configured. Set COINREMITTER_API_KEY and COINREMITTER_PASSWORD environment variables.',
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
try {
|
|
46
|
+
const invoiceData = await apiRequest('create-invoice', {
|
|
47
|
+
amount: request.amount,
|
|
48
|
+
currency: 'USD', // Amount is in USD, will convert to USDT
|
|
49
|
+
name: request.agentId,
|
|
50
|
+
description: request.description || `Deposit for ${request.agentId}`,
|
|
51
|
+
notify_url: COINREMITTER_WEBHOOK_URL,
|
|
52
|
+
expire_time: 30, // 30 minutes
|
|
53
|
+
custom_data1: request.agentId,
|
|
54
|
+
});
|
|
55
|
+
const expiresAt = new Date(invoiceData.expire_time);
|
|
56
|
+
return {
|
|
57
|
+
success: true,
|
|
58
|
+
deposit: {
|
|
59
|
+
id: `cr_${invoiceData.invoice_id}`,
|
|
60
|
+
agentId: request.agentId,
|
|
61
|
+
amount: request.amount,
|
|
62
|
+
currency: 'USDT',
|
|
63
|
+
network: 'trc20',
|
|
64
|
+
status: 'pending',
|
|
65
|
+
provider: 'coinremitter',
|
|
66
|
+
externalId: invoiceData.invoice_id,
|
|
67
|
+
paymentAddress: invoiceData.address,
|
|
68
|
+
paymentUrl: invoiceData.url,
|
|
69
|
+
createdAt: new Date(),
|
|
70
|
+
expiresAt,
|
|
71
|
+
completedAt: null,
|
|
72
|
+
txHash: null,
|
|
73
|
+
},
|
|
74
|
+
invoice: invoiceData,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
catch (error) {
|
|
78
|
+
return {
|
|
79
|
+
success: false,
|
|
80
|
+
error: error instanceof Error ? error.message : 'Failed to create invoice',
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Check invoice status
|
|
86
|
+
*/
|
|
87
|
+
export async function getInvoiceStatus(invoiceId) {
|
|
88
|
+
if (!COINREMITTER_API_KEY || !COINREMITTER_PASSWORD) {
|
|
89
|
+
return { success: false, error: 'CoinRemitter credentials not configured' };
|
|
90
|
+
}
|
|
91
|
+
try {
|
|
92
|
+
const data = await apiRequest('get-invoice', { invoice_id: invoiceId });
|
|
93
|
+
return {
|
|
94
|
+
success: true,
|
|
95
|
+
status: data.status,
|
|
96
|
+
paid: data.status === 'Paid',
|
|
97
|
+
amount: parseFloat(data.paid_amount?.USD || '0'),
|
|
98
|
+
txId: data.transaction_id,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
catch (error) {
|
|
102
|
+
return {
|
|
103
|
+
success: false,
|
|
104
|
+
error: error instanceof Error ? error.message : 'Failed to get invoice status',
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Process webhook callback from CoinRemitter
|
|
110
|
+
*/
|
|
111
|
+
export function parseWebhookPayload(body) {
|
|
112
|
+
return {
|
|
113
|
+
invoiceId: body.invoice_id,
|
|
114
|
+
status: body.status,
|
|
115
|
+
amount: parseFloat(body.usd_amount || body.coin_amount || '0'),
|
|
116
|
+
agentId: body.custom_data1,
|
|
117
|
+
txId: body.transaction_id || null,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Send USDT withdrawal
|
|
122
|
+
*/
|
|
123
|
+
export async function sendCoinRemitterWithdrawal(toAddress, amount) {
|
|
124
|
+
if (!COINREMITTER_API_KEY || !COINREMITTER_PASSWORD) {
|
|
125
|
+
return { success: false, error: 'CoinRemitter credentials not configured' };
|
|
126
|
+
}
|
|
127
|
+
try {
|
|
128
|
+
const data = await apiRequest('withdraw', {
|
|
129
|
+
to_address: toAddress,
|
|
130
|
+
amount: amount,
|
|
131
|
+
currency: 'USD', // Will convert to USDT equivalent
|
|
132
|
+
});
|
|
133
|
+
return {
|
|
134
|
+
success: true,
|
|
135
|
+
txId: data.txn_id || data.id,
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
catch (error) {
|
|
139
|
+
return {
|
|
140
|
+
success: false,
|
|
141
|
+
error: error instanceof Error ? error.message : 'Failed to send withdrawal',
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Get wallet balance from CoinRemitter
|
|
147
|
+
*/
|
|
148
|
+
export async function getWalletBalance() {
|
|
149
|
+
if (!COINREMITTER_API_KEY || !COINREMITTER_PASSWORD) {
|
|
150
|
+
return { success: false, error: 'CoinRemitter credentials not configured' };
|
|
151
|
+
}
|
|
152
|
+
try {
|
|
153
|
+
const data = await apiRequest('get-balance', {});
|
|
154
|
+
return {
|
|
155
|
+
success: true,
|
|
156
|
+
balance: parseFloat(data.balance || '0'),
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
catch (error) {
|
|
160
|
+
return {
|
|
161
|
+
success: false,
|
|
162
|
+
error: error instanceof Error ? error.message : 'Failed to get balance',
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
export const coinremitterService = {
|
|
167
|
+
createDeposit: createCoinRemitterDeposit,
|
|
168
|
+
getInvoiceStatus,
|
|
169
|
+
parseWebhookPayload,
|
|
170
|
+
sendWithdrawal: sendCoinRemitterWithdrawal,
|
|
171
|
+
getWalletBalance,
|
|
172
|
+
config: {
|
|
173
|
+
configured: !!(COINREMITTER_API_KEY && COINREMITTER_PASSWORD),
|
|
174
|
+
webhookUrl: COINREMITTER_WEBHOOK_URL,
|
|
175
|
+
},
|
|
176
|
+
};
|