coinley-test 0.0.20 → 0.0.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.esm.js +603 -1
- package/dist/index.esm.js.map +1 -1
- package/dist/index.umd.js +1 -1
- package/dist/index.umd.js.map +1 -1
- package/dist/style.css +1 -1
- package/package.json +1 -1
package/dist/index.esm.js
CHANGED
|
@@ -1237,7 +1237,607 @@ const ThemeProvider = ({
|
|
|
1237
1237
|
}, [theme]);
|
|
1238
1238
|
return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: `coinley-theme-${theme}`, children });
|
|
1239
1239
|
};
|
|
1240
|
-
|
|
1240
|
+
class SimplePaymentAPI {
|
|
1241
|
+
constructor(baseURL, apiKey, apiSecret) {
|
|
1242
|
+
this.baseURL = baseURL.endsWith("/") ? baseURL.slice(0, -1) : baseURL;
|
|
1243
|
+
this.apiKey = apiKey;
|
|
1244
|
+
this.apiSecret = apiSecret;
|
|
1245
|
+
}
|
|
1246
|
+
async request(endpoint, options = {}) {
|
|
1247
|
+
const url = `${this.baseURL}${endpoint}`;
|
|
1248
|
+
const headers = {
|
|
1249
|
+
"Content-Type": "application/json",
|
|
1250
|
+
"X-API-Key": this.apiKey,
|
|
1251
|
+
"X-API-Secret": this.apiSecret,
|
|
1252
|
+
...options.headers
|
|
1253
|
+
};
|
|
1254
|
+
const response = await fetch(url, {
|
|
1255
|
+
...options,
|
|
1256
|
+
headers
|
|
1257
|
+
});
|
|
1258
|
+
if (!response.ok) {
|
|
1259
|
+
const error = await response.json().catch(() => ({}));
|
|
1260
|
+
throw new Error(error.error || `HTTP ${response.status}`);
|
|
1261
|
+
}
|
|
1262
|
+
return response.json();
|
|
1263
|
+
}
|
|
1264
|
+
async getNetworks() {
|
|
1265
|
+
try {
|
|
1266
|
+
return await this.request("/api/networks");
|
|
1267
|
+
} catch (error) {
|
|
1268
|
+
console.error("Failed to fetch networks:", error);
|
|
1269
|
+
return {
|
|
1270
|
+
networks: [
|
|
1271
|
+
{ id: "1", name: "Ethereum", shortName: "ethereum", chainId: "0x1", type: "ethereum" },
|
|
1272
|
+
{ id: "56", name: "BSC", shortName: "bsc", chainId: "0x38", type: "bsc" }
|
|
1273
|
+
]
|
|
1274
|
+
};
|
|
1275
|
+
}
|
|
1276
|
+
}
|
|
1277
|
+
async getTokens() {
|
|
1278
|
+
try {
|
|
1279
|
+
return await this.request("/api/networks/stablecoins");
|
|
1280
|
+
} catch (error) {
|
|
1281
|
+
console.error("Failed to fetch tokens:", error);
|
|
1282
|
+
return {
|
|
1283
|
+
stablecoins: [
|
|
1284
|
+
{
|
|
1285
|
+
id: "1",
|
|
1286
|
+
name: "Tether USD",
|
|
1287
|
+
symbol: "USDT",
|
|
1288
|
+
contractAddress: "0xdAC17F958D2ee523a2206206994597C13D831ec7",
|
|
1289
|
+
decimals: 6,
|
|
1290
|
+
networkId: "1",
|
|
1291
|
+
Network: { shortName: "ethereum", name: "Ethereum" }
|
|
1292
|
+
}
|
|
1293
|
+
]
|
|
1294
|
+
};
|
|
1295
|
+
}
|
|
1296
|
+
}
|
|
1297
|
+
async createPayment(data) {
|
|
1298
|
+
return await this.request("/api/payments/create", {
|
|
1299
|
+
method: "POST",
|
|
1300
|
+
body: JSON.stringify(data)
|
|
1301
|
+
});
|
|
1302
|
+
}
|
|
1303
|
+
}
|
|
1304
|
+
class SimpleMetaMaskWallet {
|
|
1305
|
+
constructor() {
|
|
1306
|
+
this.account = null;
|
|
1307
|
+
this.chainId = null;
|
|
1308
|
+
}
|
|
1309
|
+
async connect() {
|
|
1310
|
+
if (!window.ethereum) {
|
|
1311
|
+
throw new Error("MetaMask not installed. Please install MetaMask extension.");
|
|
1312
|
+
}
|
|
1313
|
+
if (window.ethereum.providers) {
|
|
1314
|
+
console.log("🔍 Multiple wallets detected:", window.ethereum.providers.length);
|
|
1315
|
+
const metamaskProvider = window.ethereum.providers.find((provider) => provider.isMetaMask);
|
|
1316
|
+
if (!metamaskProvider) {
|
|
1317
|
+
throw new Error("MetaMask not found among installed wallets");
|
|
1318
|
+
}
|
|
1319
|
+
console.log("🦊 Using MetaMask provider specifically");
|
|
1320
|
+
window.ethereum = metamaskProvider;
|
|
1321
|
+
} else if (!window.ethereum.isMetaMask) {
|
|
1322
|
+
throw new Error("Please use MetaMask wallet");
|
|
1323
|
+
}
|
|
1324
|
+
try {
|
|
1325
|
+
console.log("🦊 Requesting MetaMask account access...");
|
|
1326
|
+
const accounts = await window.ethereum.request({
|
|
1327
|
+
method: "eth_requestAccounts"
|
|
1328
|
+
});
|
|
1329
|
+
if (!accounts || accounts.length === 0) {
|
|
1330
|
+
throw new Error("No accounts found in MetaMask");
|
|
1331
|
+
}
|
|
1332
|
+
const chainId = await window.ethereum.request({
|
|
1333
|
+
method: "eth_chainId"
|
|
1334
|
+
});
|
|
1335
|
+
this.account = accounts[0];
|
|
1336
|
+
this.chainId = chainId;
|
|
1337
|
+
console.log("✅ MetaMask connected successfully:");
|
|
1338
|
+
console.log(" Account:", this.account);
|
|
1339
|
+
console.log(" Chain ID:", this.chainId);
|
|
1340
|
+
if (this.account.toLowerCase() !== "0xa0419a048a1469b34a5245f08c0697ba956a56ab") {
|
|
1341
|
+
console.warn("⚠️ Connected to different account than expected");
|
|
1342
|
+
console.warn(" Expected: 0xa0419a048A1469B34a5245f08C0697Ba956a56Ab");
|
|
1343
|
+
console.warn(" Connected:", this.account);
|
|
1344
|
+
throw new Error(`Please switch MetaMask to account 0xa041...56Ab. Currently connected to ${this.account.slice(0, 6)}...${this.account.slice(-4)}`);
|
|
1345
|
+
}
|
|
1346
|
+
return { account: this.account, chainId: this.chainId };
|
|
1347
|
+
} catch (error) {
|
|
1348
|
+
console.error("MetaMask connection failed:", error);
|
|
1349
|
+
throw new Error(error.message || "Failed to connect to MetaMask");
|
|
1350
|
+
}
|
|
1351
|
+
}
|
|
1352
|
+
async sendTransaction(txParams) {
|
|
1353
|
+
if (!this.account) {
|
|
1354
|
+
throw new Error("Wallet not connected");
|
|
1355
|
+
}
|
|
1356
|
+
try {
|
|
1357
|
+
console.log("🦊 Sending MetaMask transaction:", txParams);
|
|
1358
|
+
if (!window.ethereum.isMetaMask) {
|
|
1359
|
+
throw new Error("Not using MetaMask provider");
|
|
1360
|
+
}
|
|
1361
|
+
if (txParams.data && txParams.data.includes("a9059cbb")) {
|
|
1362
|
+
console.log("🔍 Checking USDT balance...");
|
|
1363
|
+
try {
|
|
1364
|
+
const balanceHex = await window.ethereum.request({
|
|
1365
|
+
method: "eth_call",
|
|
1366
|
+
params: [{
|
|
1367
|
+
to: txParams.to,
|
|
1368
|
+
// USDT contract
|
|
1369
|
+
data: `0x70a08231000000000000000000000000${this.account.slice(2)}`
|
|
1370
|
+
// balanceOf(address)
|
|
1371
|
+
}, "latest"]
|
|
1372
|
+
});
|
|
1373
|
+
const balance = parseInt(balanceHex, 16);
|
|
1374
|
+
const balanceUSDT = balance / 1e6;
|
|
1375
|
+
console.log("💰 USDT Balance:", balanceUSDT);
|
|
1376
|
+
const amountHex = txParams.data.slice(-64);
|
|
1377
|
+
const transactionAmount = parseInt(amountHex, 16);
|
|
1378
|
+
const transactionAmountUSDT = transactionAmount / 1e6;
|
|
1379
|
+
console.log("💸 Transaction Amount:", transactionAmountUSDT);
|
|
1380
|
+
if (balance < transactionAmount) {
|
|
1381
|
+
throw new Error(`Insufficient USDT balance. You have ${balanceUSDT} USDT but need ${transactionAmountUSDT} USDT`);
|
|
1382
|
+
}
|
|
1383
|
+
} catch (balanceError) {
|
|
1384
|
+
console.warn("Could not check balance:", balanceError);
|
|
1385
|
+
}
|
|
1386
|
+
}
|
|
1387
|
+
try {
|
|
1388
|
+
const ethBalanceHex = await window.ethereum.request({
|
|
1389
|
+
method: "eth_getBalance",
|
|
1390
|
+
params: [this.account, "latest"]
|
|
1391
|
+
});
|
|
1392
|
+
const ethBalance = parseInt(ethBalanceHex, 16) / Math.pow(10, 18);
|
|
1393
|
+
console.log("⛽ ETH Balance for gas:", ethBalance);
|
|
1394
|
+
if (ethBalance < 1e-3) {
|
|
1395
|
+
throw new Error(`Insufficient ETH for gas fees. You have ${ethBalance.toFixed(4)} ETH but need at least 0.001 ETH`);
|
|
1396
|
+
}
|
|
1397
|
+
} catch (gasError) {
|
|
1398
|
+
console.warn("Could not check ETH balance:", gasError);
|
|
1399
|
+
}
|
|
1400
|
+
const fullTxParams = {
|
|
1401
|
+
...txParams,
|
|
1402
|
+
from: this.account
|
|
1403
|
+
};
|
|
1404
|
+
try {
|
|
1405
|
+
const gasEstimate = await window.ethereum.request({
|
|
1406
|
+
method: "eth_estimateGas",
|
|
1407
|
+
params: [fullTxParams]
|
|
1408
|
+
});
|
|
1409
|
+
const gasLimit = Math.floor(parseInt(gasEstimate, 16) * 1.2);
|
|
1410
|
+
fullTxParams.gas = `0x${gasLimit.toString(16)}`;
|
|
1411
|
+
console.log("⛽ Gas estimate:", parseInt(gasEstimate, 16));
|
|
1412
|
+
console.log("⛽ Gas limit (with buffer):", gasLimit);
|
|
1413
|
+
} catch (gasError) {
|
|
1414
|
+
console.warn("Gas estimation failed:", gasError);
|
|
1415
|
+
fullTxParams.gas = "0x15F90";
|
|
1416
|
+
}
|
|
1417
|
+
console.log("📤 Final transaction params:", fullTxParams);
|
|
1418
|
+
const txHash = await window.ethereum.request({
|
|
1419
|
+
method: "eth_sendTransaction",
|
|
1420
|
+
params: [fullTxParams]
|
|
1421
|
+
});
|
|
1422
|
+
console.log("✅ Transaction sent successfully:", txHash);
|
|
1423
|
+
return txHash;
|
|
1424
|
+
} catch (error) {
|
|
1425
|
+
console.error("Transaction failed:", error);
|
|
1426
|
+
if (error.code === 4001) {
|
|
1427
|
+
throw new Error("Transaction cancelled by user");
|
|
1428
|
+
} else if (error.message.includes("insufficient funds")) {
|
|
1429
|
+
throw new Error("Insufficient funds in wallet");
|
|
1430
|
+
} else if (error.message.includes("gas")) {
|
|
1431
|
+
throw new Error("Gas estimation failed. You may not have enough ETH for gas fees.");
|
|
1432
|
+
} else if (error.message.includes("invalid opcode")) {
|
|
1433
|
+
throw new Error("Transaction failed - invalid operation. This usually means insufficient token balance or contract interaction failed.");
|
|
1434
|
+
} else {
|
|
1435
|
+
throw new Error(error.message || "Transaction failed");
|
|
1436
|
+
}
|
|
1437
|
+
}
|
|
1438
|
+
}
|
|
1439
|
+
isConnected() {
|
|
1440
|
+
return !!this.account;
|
|
1441
|
+
}
|
|
1442
|
+
}
|
|
1443
|
+
const SimpleCoinleyPayment = ({
|
|
1444
|
+
apiKey,
|
|
1445
|
+
apiSecret,
|
|
1446
|
+
apiUrl,
|
|
1447
|
+
config,
|
|
1448
|
+
onSuccess,
|
|
1449
|
+
onError,
|
|
1450
|
+
onClose,
|
|
1451
|
+
isOpen,
|
|
1452
|
+
theme = "light"
|
|
1453
|
+
}) => {
|
|
1454
|
+
var _a, _b;
|
|
1455
|
+
const [currentStep, setCurrentStep] = useState("method");
|
|
1456
|
+
const [networks, setNetworks] = useState([]);
|
|
1457
|
+
const [tokens, setTokens] = useState([]);
|
|
1458
|
+
const [selectedNetwork, setSelectedNetwork] = useState(null);
|
|
1459
|
+
const [selectedToken, setSelectedToken] = useState(null);
|
|
1460
|
+
const [paymentMethod, setPaymentMethod] = useState(null);
|
|
1461
|
+
const [paymentData, setPaymentData] = useState(null);
|
|
1462
|
+
const [loading, setLoading] = useState(false);
|
|
1463
|
+
const [error, setError] = useState("");
|
|
1464
|
+
const [wallet, setWallet] = useState(new SimpleMetaMaskWallet());
|
|
1465
|
+
const [walletConnected, setWalletConnected] = useState(false);
|
|
1466
|
+
const [processing, setProcessing] = useState(false);
|
|
1467
|
+
const api = useRef(new SimplePaymentAPI(apiUrl, apiKey, apiSecret));
|
|
1468
|
+
useEffect(() => {
|
|
1469
|
+
if (isOpen) {
|
|
1470
|
+
loadData();
|
|
1471
|
+
resetState();
|
|
1472
|
+
}
|
|
1473
|
+
}, [isOpen]);
|
|
1474
|
+
const resetState = () => {
|
|
1475
|
+
setCurrentStep("method");
|
|
1476
|
+
setSelectedNetwork(null);
|
|
1477
|
+
setSelectedToken(null);
|
|
1478
|
+
setPaymentMethod(null);
|
|
1479
|
+
setPaymentData(null);
|
|
1480
|
+
setError("");
|
|
1481
|
+
setWalletConnected(false);
|
|
1482
|
+
setProcessing(false);
|
|
1483
|
+
setWallet(new SimpleMetaMaskWallet());
|
|
1484
|
+
};
|
|
1485
|
+
const loadData = async () => {
|
|
1486
|
+
var _a2, _b2;
|
|
1487
|
+
try {
|
|
1488
|
+
setLoading(true);
|
|
1489
|
+
setError("");
|
|
1490
|
+
console.log("🔄 Loading networks and tokens...");
|
|
1491
|
+
const [networksRes, tokensRes] = await Promise.all([
|
|
1492
|
+
api.current.getNetworks(),
|
|
1493
|
+
api.current.getTokens()
|
|
1494
|
+
]);
|
|
1495
|
+
setNetworks(networksRes.networks || []);
|
|
1496
|
+
setTokens(tokensRes.stablecoins || []);
|
|
1497
|
+
console.log("✅ Loaded networks:", (_a2 = networksRes.networks) == null ? void 0 : _a2.length);
|
|
1498
|
+
console.log("✅ Loaded tokens:", (_b2 = tokensRes.stablecoins) == null ? void 0 : _b2.length);
|
|
1499
|
+
} catch (err) {
|
|
1500
|
+
console.error("Failed to load data:", err);
|
|
1501
|
+
setError("Failed to load payment options. Using fallback data.");
|
|
1502
|
+
} finally {
|
|
1503
|
+
setLoading(false);
|
|
1504
|
+
}
|
|
1505
|
+
};
|
|
1506
|
+
const connectWallet = async () => {
|
|
1507
|
+
try {
|
|
1508
|
+
setLoading(true);
|
|
1509
|
+
setError("");
|
|
1510
|
+
const connection = await wallet.connect();
|
|
1511
|
+
setWalletConnected(true);
|
|
1512
|
+
console.log("✅ Wallet connected successfully:", connection.account);
|
|
1513
|
+
} catch (err) {
|
|
1514
|
+
console.error("Wallet connection failed:", err);
|
|
1515
|
+
setError(err.message);
|
|
1516
|
+
} finally {
|
|
1517
|
+
setLoading(false);
|
|
1518
|
+
}
|
|
1519
|
+
};
|
|
1520
|
+
const createPayment = async () => {
|
|
1521
|
+
try {
|
|
1522
|
+
setLoading(true);
|
|
1523
|
+
setError("");
|
|
1524
|
+
const paymentPayload = {
|
|
1525
|
+
amount: config.amount,
|
|
1526
|
+
currency: selectedToken.symbol,
|
|
1527
|
+
network: selectedNetwork.shortName,
|
|
1528
|
+
customerEmail: config.customerEmail,
|
|
1529
|
+
callbackUrl: config.callbackUrl,
|
|
1530
|
+
metadata: {
|
|
1531
|
+
...config.metadata,
|
|
1532
|
+
merchantWalletAddresses: config.merchantWalletAddresses,
|
|
1533
|
+
paymentMethod,
|
|
1534
|
+
selectedNetwork: selectedNetwork.shortName,
|
|
1535
|
+
selectedToken: selectedToken.symbol
|
|
1536
|
+
}
|
|
1537
|
+
};
|
|
1538
|
+
console.log("🔄 Creating payment:", paymentPayload);
|
|
1539
|
+
const payment = await api.current.createPayment(paymentPayload);
|
|
1540
|
+
setPaymentData(payment.payment);
|
|
1541
|
+
console.log("✅ Payment created:", payment.payment.id);
|
|
1542
|
+
if (paymentMethod === "wallet") {
|
|
1543
|
+
setCurrentStep("wallet");
|
|
1544
|
+
} else {
|
|
1545
|
+
setCurrentStep("qr");
|
|
1546
|
+
}
|
|
1547
|
+
} catch (err) {
|
|
1548
|
+
console.error("Payment creation failed:", err);
|
|
1549
|
+
setError(err.message);
|
|
1550
|
+
} finally {
|
|
1551
|
+
setLoading(false);
|
|
1552
|
+
}
|
|
1553
|
+
};
|
|
1554
|
+
const sendTransaction = async () => {
|
|
1555
|
+
var _a2, _b2;
|
|
1556
|
+
try {
|
|
1557
|
+
setProcessing(true);
|
|
1558
|
+
setError("");
|
|
1559
|
+
const recipientAddress = ((_a2 = paymentData.metadata) == null ? void 0 : _a2.recipientWallet) || ((_b2 = config.merchantWalletAddresses) == null ? void 0 : _b2[selectedNetwork.shortName]);
|
|
1560
|
+
if (!recipientAddress) {
|
|
1561
|
+
throw new Error("Merchant wallet address not found");
|
|
1562
|
+
}
|
|
1563
|
+
console.log("🔄 Preparing transaction to:", recipientAddress);
|
|
1564
|
+
let txParams;
|
|
1565
|
+
if (selectedToken.contractAddress) {
|
|
1566
|
+
const decimals = selectedToken.decimals || 6;
|
|
1567
|
+
const amount = Math.floor(paymentData.totalAmount * Math.pow(10, decimals));
|
|
1568
|
+
const methodId = "0xa9059cbb";
|
|
1569
|
+
const recipientPadded = recipientAddress.slice(2).toLowerCase().padStart(64, "0");
|
|
1570
|
+
const amountPadded = amount.toString(16).padStart(64, "0");
|
|
1571
|
+
const data = `${methodId}${recipientPadded}${amountPadded}`;
|
|
1572
|
+
txParams = {
|
|
1573
|
+
to: selectedToken.contractAddress,
|
|
1574
|
+
data,
|
|
1575
|
+
value: "0x0"
|
|
1576
|
+
};
|
|
1577
|
+
console.log("🔄 ERC-20 Transaction:", {
|
|
1578
|
+
token: selectedToken.symbol,
|
|
1579
|
+
amount: paymentData.totalAmount,
|
|
1580
|
+
amountWithDecimals: amount,
|
|
1581
|
+
to: selectedToken.contractAddress,
|
|
1582
|
+
recipient: recipientAddress
|
|
1583
|
+
});
|
|
1584
|
+
} else {
|
|
1585
|
+
const value = Math.floor(paymentData.totalAmount * Math.pow(10, 18));
|
|
1586
|
+
txParams = {
|
|
1587
|
+
to: recipientAddress,
|
|
1588
|
+
value: `0x${value.toString(16)}`
|
|
1589
|
+
};
|
|
1590
|
+
console.log("🔄 Native Transaction:", {
|
|
1591
|
+
amount: paymentData.totalAmount,
|
|
1592
|
+
to: recipientAddress
|
|
1593
|
+
});
|
|
1594
|
+
}
|
|
1595
|
+
const txHash = await wallet.sendTransaction(txParams);
|
|
1596
|
+
console.log("✅ Transaction successful:", txHash);
|
|
1597
|
+
setCurrentStep("success");
|
|
1598
|
+
onSuccess == null ? void 0 : onSuccess(paymentData.id, txHash, {
|
|
1599
|
+
network: selectedNetwork.name,
|
|
1600
|
+
token: selectedToken.symbol,
|
|
1601
|
+
amount: paymentData.totalAmount,
|
|
1602
|
+
method: paymentMethod
|
|
1603
|
+
});
|
|
1604
|
+
} catch (err) {
|
|
1605
|
+
console.error("Transaction failed:", err);
|
|
1606
|
+
setError(err.message);
|
|
1607
|
+
} finally {
|
|
1608
|
+
setProcessing(false);
|
|
1609
|
+
}
|
|
1610
|
+
};
|
|
1611
|
+
if (!isOpen) return null;
|
|
1612
|
+
const isDark = theme === "dark";
|
|
1613
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: `rounded-lg shadow-xl max-w-md w-full mx-4 ${isDark ? "bg-gray-900 text-white" : "bg-white text-gray-900"}`, children: [
|
|
1614
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: `p-4 border-b flex justify-between items-center ${isDark ? "border-gray-700" : "border-gray-200"}`, children: [
|
|
1615
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-center flex-1", children: [
|
|
1616
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("h2", { className: "text-lg font-semibold", children: "Pay with Crypto" }),
|
|
1617
|
+
config.amount && /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-2xl font-bold text-purple-600", children: [
|
|
1618
|
+
"$",
|
|
1619
|
+
config.amount.toFixed(2)
|
|
1620
|
+
] })
|
|
1621
|
+
] }),
|
|
1622
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
1623
|
+
"button",
|
|
1624
|
+
{
|
|
1625
|
+
onClick: onClose,
|
|
1626
|
+
className: `ml-4 text-gray-500 hover:text-gray-700 ${isDark ? "hover:text-gray-300" : ""}`,
|
|
1627
|
+
children: "✕"
|
|
1628
|
+
}
|
|
1629
|
+
)
|
|
1630
|
+
] }),
|
|
1631
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-4 min-h-[400px]", children: [
|
|
1632
|
+
error && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mb-4 p-3 bg-red-100 text-red-700 rounded border border-red-200", children: [
|
|
1633
|
+
error,
|
|
1634
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
1635
|
+
"button",
|
|
1636
|
+
{
|
|
1637
|
+
onClick: () => setError(""),
|
|
1638
|
+
className: "ml-2 text-red-500 hover:text-red-700",
|
|
1639
|
+
children: "✕"
|
|
1640
|
+
}
|
|
1641
|
+
)
|
|
1642
|
+
] }),
|
|
1643
|
+
currentStep === "method" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-4", children: [
|
|
1644
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "font-medium text-center mb-6", children: "Choose Payment Method" }),
|
|
1645
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-3", children: [
|
|
1646
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
1647
|
+
"button",
|
|
1648
|
+
{
|
|
1649
|
+
onClick: () => {
|
|
1650
|
+
setPaymentMethod("wallet");
|
|
1651
|
+
setCurrentStep("network");
|
|
1652
|
+
},
|
|
1653
|
+
className: `w-full p-4 border-2 rounded-lg hover:border-purple-500 text-left flex items-center space-x-3 transition-colors ${isDark ? "border-gray-600 hover:bg-gray-800" : "border-gray-200 hover:bg-gray-50"}`,
|
|
1654
|
+
children: [
|
|
1655
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-2xl", children: "🦊" }),
|
|
1656
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
|
|
1657
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "font-medium", children: "MetaMask Wallet" }),
|
|
1658
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: `text-sm ${isDark ? "text-gray-400" : "text-gray-500"}`, children: "Connect and pay instantly" })
|
|
1659
|
+
] })
|
|
1660
|
+
]
|
|
1661
|
+
}
|
|
1662
|
+
),
|
|
1663
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
1664
|
+
"button",
|
|
1665
|
+
{
|
|
1666
|
+
onClick: () => {
|
|
1667
|
+
setPaymentMethod("qr");
|
|
1668
|
+
setCurrentStep("network");
|
|
1669
|
+
},
|
|
1670
|
+
className: `w-full p-4 border-2 rounded-lg hover:border-purple-500 text-left flex items-center space-x-3 transition-colors ${isDark ? "border-gray-600 hover:bg-gray-800" : "border-gray-200 hover:bg-gray-50"}`,
|
|
1671
|
+
children: [
|
|
1672
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-2xl", children: "📱" }),
|
|
1673
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
|
|
1674
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "font-medium", children: "QR Code" }),
|
|
1675
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: `text-sm ${isDark ? "text-gray-400" : "text-gray-500"}`, children: "Scan with mobile wallet" })
|
|
1676
|
+
] })
|
|
1677
|
+
]
|
|
1678
|
+
}
|
|
1679
|
+
)
|
|
1680
|
+
] })
|
|
1681
|
+
] }),
|
|
1682
|
+
currentStep === "network" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-4", children: [
|
|
1683
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center space-x-2", children: [
|
|
1684
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
1685
|
+
"button",
|
|
1686
|
+
{
|
|
1687
|
+
onClick: () => setCurrentStep("method"),
|
|
1688
|
+
className: `${isDark ? "text-gray-400 hover:text-gray-200" : "text-gray-500 hover:text-gray-700"}`,
|
|
1689
|
+
children: "←"
|
|
1690
|
+
}
|
|
1691
|
+
),
|
|
1692
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "font-medium", children: "Select Network" })
|
|
1693
|
+
] }),
|
|
1694
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "space-y-2", children: networks.map((network) => /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
1695
|
+
"button",
|
|
1696
|
+
{
|
|
1697
|
+
onClick: () => {
|
|
1698
|
+
setSelectedNetwork(network);
|
|
1699
|
+
setCurrentStep("token");
|
|
1700
|
+
},
|
|
1701
|
+
className: `w-full p-3 border rounded-lg hover:border-purple-500 text-left transition-colors ${isDark ? "border-gray-600 hover:bg-gray-800" : "border-gray-200 hover:bg-gray-50"}`,
|
|
1702
|
+
children: [
|
|
1703
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "font-medium", children: network.name }),
|
|
1704
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: `text-sm ${isDark ? "text-gray-400" : "text-gray-500"}`, children: network.shortName.toUpperCase() })
|
|
1705
|
+
]
|
|
1706
|
+
},
|
|
1707
|
+
network.id
|
|
1708
|
+
)) })
|
|
1709
|
+
] }),
|
|
1710
|
+
currentStep === "token" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-4", children: [
|
|
1711
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center space-x-2", children: [
|
|
1712
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
1713
|
+
"button",
|
|
1714
|
+
{
|
|
1715
|
+
onClick: () => setCurrentStep("network"),
|
|
1716
|
+
className: `${isDark ? "text-gray-400 hover:text-gray-200" : "text-gray-500 hover:text-gray-700"}`,
|
|
1717
|
+
children: "←"
|
|
1718
|
+
}
|
|
1719
|
+
),
|
|
1720
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("h3", { className: "font-medium", children: [
|
|
1721
|
+
"Select Token on ",
|
|
1722
|
+
selectedNetwork == null ? void 0 : selectedNetwork.name
|
|
1723
|
+
] })
|
|
1724
|
+
] }),
|
|
1725
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "space-y-2", children: tokens.filter((token) => {
|
|
1726
|
+
var _a2;
|
|
1727
|
+
return ((_a2 = token.Network) == null ? void 0 : _a2.shortName) === (selectedNetwork == null ? void 0 : selectedNetwork.shortName);
|
|
1728
|
+
}).map((token) => /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
1729
|
+
"button",
|
|
1730
|
+
{
|
|
1731
|
+
onClick: () => {
|
|
1732
|
+
setSelectedToken(token);
|
|
1733
|
+
createPayment();
|
|
1734
|
+
},
|
|
1735
|
+
disabled: loading,
|
|
1736
|
+
className: `w-full p-3 border rounded-lg hover:border-purple-500 text-left flex justify-between transition-colors disabled:opacity-50 ${isDark ? "border-gray-600 hover:bg-gray-800" : "border-gray-200 hover:bg-gray-50"}`,
|
|
1737
|
+
children: [
|
|
1738
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
|
|
1739
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "font-medium", children: token.name }),
|
|
1740
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: `text-sm ${isDark ? "text-gray-400" : "text-gray-500"}`, children: token.symbol })
|
|
1741
|
+
] }),
|
|
1742
|
+
token.isStablecoin && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "px-2 py-1 bg-green-100 text-green-600 text-xs rounded", children: "Stablecoin" })
|
|
1743
|
+
]
|
|
1744
|
+
},
|
|
1745
|
+
token.id
|
|
1746
|
+
)) })
|
|
1747
|
+
] }),
|
|
1748
|
+
currentStep === "wallet" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-4", children: [
|
|
1749
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "font-medium text-center", children: "Connect & Pay" }),
|
|
1750
|
+
!walletConnected ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-center space-y-4", children: [
|
|
1751
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-16 h-16 bg-purple-100 rounded-full flex items-center justify-center mx-auto", children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-2xl", children: "🦊" }) }),
|
|
1752
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: `${isDark ? "text-gray-300" : "text-gray-600"}`, children: "Connect MetaMask to continue" }),
|
|
1753
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
1754
|
+
"button",
|
|
1755
|
+
{
|
|
1756
|
+
onClick: connectWallet,
|
|
1757
|
+
disabled: loading,
|
|
1758
|
+
className: "w-full bg-purple-600 text-white py-3 px-4 rounded-lg hover:bg-purple-700 disabled:opacity-50 font-medium",
|
|
1759
|
+
children: loading ? "Connecting..." : "Connect MetaMask"
|
|
1760
|
+
}
|
|
1761
|
+
)
|
|
1762
|
+
] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-4", children: [
|
|
1763
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-3 bg-green-50 rounded-lg border border-green-200", children: [
|
|
1764
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-green-600 text-sm font-medium", children: "✅ Wallet Connected" }),
|
|
1765
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "font-mono text-xs text-green-700 mt-1", children: [
|
|
1766
|
+
(_a = wallet.account) == null ? void 0 : _a.slice(0, 6),
|
|
1767
|
+
"...",
|
|
1768
|
+
(_b = wallet.account) == null ? void 0 : _b.slice(-4)
|
|
1769
|
+
] })
|
|
1770
|
+
] }),
|
|
1771
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: `p-4 rounded-lg space-y-2 ${isDark ? "bg-gray-800" : "bg-gray-50"}`, children: [
|
|
1772
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between text-sm", children: [
|
|
1773
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Amount:" }),
|
|
1774
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-medium", children: [
|
|
1775
|
+
paymentData == null ? void 0 : paymentData.totalAmount,
|
|
1776
|
+
" ",
|
|
1777
|
+
selectedToken == null ? void 0 : selectedToken.symbol
|
|
1778
|
+
] })
|
|
1779
|
+
] }),
|
|
1780
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between text-sm", children: [
|
|
1781
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Network:" }),
|
|
1782
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-medium", children: selectedNetwork == null ? void 0 : selectedNetwork.name })
|
|
1783
|
+
] }),
|
|
1784
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between text-sm", children: [
|
|
1785
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Token:" }),
|
|
1786
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-medium", children: selectedToken == null ? void 0 : selectedToken.name })
|
|
1787
|
+
] })
|
|
1788
|
+
] }),
|
|
1789
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
1790
|
+
"button",
|
|
1791
|
+
{
|
|
1792
|
+
onClick: sendTransaction,
|
|
1793
|
+
disabled: processing,
|
|
1794
|
+
className: "w-full bg-green-600 text-white py-3 px-4 rounded-lg hover:bg-green-700 disabled:opacity-50 font-medium flex items-center justify-center space-x-2",
|
|
1795
|
+
children: processing ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
1796
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "animate-spin rounded-full h-4 w-4 border-b-2 border-white" }),
|
|
1797
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Sending Transaction..." })
|
|
1798
|
+
] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [
|
|
1799
|
+
"Send ",
|
|
1800
|
+
paymentData == null ? void 0 : paymentData.totalAmount,
|
|
1801
|
+
" ",
|
|
1802
|
+
selectedToken == null ? void 0 : selectedToken.symbol
|
|
1803
|
+
] })
|
|
1804
|
+
}
|
|
1805
|
+
)
|
|
1806
|
+
] })
|
|
1807
|
+
] }),
|
|
1808
|
+
currentStep === "qr" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-center space-y-4", children: [
|
|
1809
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "font-medium", children: "Scan QR Code" }),
|
|
1810
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: `p-8 rounded-lg ${isDark ? "bg-gray-800" : "bg-gray-100"}`, children: [
|
|
1811
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: `${isDark ? "text-gray-400" : "text-gray-500"}`, children: "QR Code will appear here" }),
|
|
1812
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-xs mt-2", children: [
|
|
1813
|
+
"Send ",
|
|
1814
|
+
paymentData == null ? void 0 : paymentData.totalAmount,
|
|
1815
|
+
" ",
|
|
1816
|
+
selectedToken == null ? void 0 : selectedToken.symbol
|
|
1817
|
+
] }),
|
|
1818
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs", children: "to merchant wallet" })
|
|
1819
|
+
] }),
|
|
1820
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: `text-xs ${isDark ? "text-gray-400" : "text-gray-500"}`, children: "Waiting for payment confirmation..." })
|
|
1821
|
+
] }),
|
|
1822
|
+
currentStep === "success" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-center space-y-4", children: [
|
|
1823
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-16 h-16 bg-green-100 rounded-full flex items-center justify-center mx-auto", children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-2xl", children: "✅" }) }),
|
|
1824
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "font-medium text-green-600", children: "Payment Successful!" }),
|
|
1825
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: `text-sm ${isDark ? "text-gray-300" : "text-gray-600"}`, children: "Your transaction has been sent successfully" }),
|
|
1826
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
1827
|
+
"button",
|
|
1828
|
+
{
|
|
1829
|
+
onClick: onClose,
|
|
1830
|
+
className: "w-full bg-purple-600 text-white py-3 px-4 rounded-lg hover:bg-purple-700 font-medium",
|
|
1831
|
+
children: "Close"
|
|
1832
|
+
}
|
|
1833
|
+
)
|
|
1834
|
+
] }),
|
|
1835
|
+
loading && currentStep !== "wallet" && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center justify-center py-8", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "animate-spin rounded-full h-8 w-8 border-b-2 border-purple-600" }) })
|
|
1836
|
+
] })
|
|
1837
|
+
] }) });
|
|
1838
|
+
};
|
|
1839
|
+
const SimpleCoinleyProvider = ({ children, ...props }) => children;
|
|
1840
|
+
const VERSION = "0.0.1";
|
|
1241
1841
|
const utils = {
|
|
1242
1842
|
formatAmount: (amount, decimals = 2) => amount.toFixed(decimals),
|
|
1243
1843
|
truncateAddress: (address, startChars = 6, endChars = 4) => {
|
|
@@ -1289,6 +1889,8 @@ export {
|
|
|
1289
1889
|
CoinleyProvider,
|
|
1290
1890
|
DEFAULT_CONFIG,
|
|
1291
1891
|
PaymentAPI,
|
|
1892
|
+
SimpleCoinleyPayment,
|
|
1893
|
+
SimpleCoinleyProvider,
|
|
1292
1894
|
ThemeProvider,
|
|
1293
1895
|
VERSION,
|
|
1294
1896
|
useCoinley,
|