@kwespay/widget 1.0.7 → 1.0.9
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 +118 -28
- package/dist/esm/index--_dPnlv5.js +2553 -0
- package/dist/esm/index-BDgXWGKX.js +2598 -0
- package/dist/esm/index-BL1KrVhv.js +2540 -0
- package/dist/esm/index-BRvdL-Wp.js +3085 -0
- package/dist/esm/index-Bd9oDICQ.js +3085 -0
- package/dist/esm/index-Bu22k5YO.js +2562 -0
- package/dist/esm/{index-338l55OY.js → index-C5OB57Yl.js} +87 -44
- package/dist/esm/index-C7bWyK3p.js +2449 -0
- package/dist/esm/index-CEIKLFls.js +2562 -0
- package/dist/esm/index-CQIWeG1B.js +3083 -0
- package/dist/esm/index-ChlX7kVk.js +2530 -0
- package/dist/esm/index-DKT22_47.js +2601 -0
- package/dist/esm/index-DLb23sAI.js +2562 -0
- package/dist/esm/index-DSz-IL-x.js +2515 -0
- package/dist/esm/index-Dm1jCXcL.js +2540 -0
- package/dist/esm/index-DrZ7hcts.js +2602 -0
- package/dist/esm/index-Ds5OUtZv.js +2552 -0
- package/dist/esm/index-ZsnaJECC.js +3085 -0
- package/dist/esm/index-azjjYn2F.js +2553 -0
- package/dist/esm/index-hxHZv-eJ.js +3085 -0
- package/dist/esm/index.js +1200 -546
- package/dist/index.d.ts +52 -5
- package/dist/kwespay-widget.js +46648 -53965
- package/dist/kwespay-widget.min.js +551 -576
- package/package.json +2 -2
|
@@ -7,15 +7,16 @@ class KwesPayError extends Error {
|
|
|
7
7
|
}
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
const ENDPOINT = "https://
|
|
10
|
+
const ENDPOINT = "https://839e-154-161-230-28.ngrok-free.app/graphql";
|
|
11
11
|
const TESTNET_CONTRACTS = {
|
|
12
|
-
sepolia: "
|
|
13
|
-
baseSepolia: "
|
|
14
|
-
polygonAmoy: "
|
|
15
|
-
liskTestnet: "
|
|
12
|
+
sepolia: "0xFC0A3A00008B79f080648A12FFb07dDE3C34F789",
|
|
13
|
+
baseSepolia: "0x8662EEA4eACCAef3e5c33c50Ac3a2b9B1B0033c7",
|
|
14
|
+
polygonAmoy: "0xc46E4D2005014990F600741A2Ce189f8118CB58e",
|
|
15
|
+
liskTestnet: "0xe0daD0d9e7413AA06859d26A552fD6a07855B070",
|
|
16
|
+
mezoTestnet: "0xa430B2e0D1273464809f8541286058e90781DA9C",
|
|
16
17
|
};
|
|
17
18
|
const MAINNET_CONTRACTS = {
|
|
18
|
-
// lisk:
|
|
19
|
+
// lisk: "0x...",
|
|
19
20
|
};
|
|
20
21
|
const CONTRACT_ADDRESSES = {
|
|
21
22
|
...TESTNET_CONTRACTS,
|
|
@@ -105,6 +106,7 @@ const GQL_CREATE_TRANSACTION = `
|
|
|
105
106
|
tokenAddress
|
|
106
107
|
amountBaseUnits
|
|
107
108
|
chainId
|
|
109
|
+
deadline
|
|
108
110
|
expiresAt
|
|
109
111
|
transaction {
|
|
110
112
|
transactionReference
|
|
@@ -2624,7 +2626,7 @@ function encodeFunctionData(parameters) {
|
|
|
2624
2626
|
|
|
2625
2627
|
const ZERO_ADDRESS$1 = "0x0000000000000000000000000000000000000000";
|
|
2626
2628
|
const PAYMENT_ABI = parseAbi([
|
|
2627
|
-
"function createPayment(bytes32 paymentId, string vendorId, address token, uint256 amount, bytes backendSignature) external payable",
|
|
2629
|
+
"function createPayment(bytes32 paymentId, string vendorId, address token, uint256 amount, uint256 deadline, bytes backendSignature) external payable",
|
|
2628
2630
|
]);
|
|
2629
2631
|
const ERC20_ABI = parseAbi([
|
|
2630
2632
|
"function allowance(address owner, address spender) view returns (uint256)",
|
|
@@ -2724,6 +2726,7 @@ class ContractService {
|
|
|
2724
2726
|
params.vendorIdentifier,
|
|
2725
2727
|
ensure0x(params.tokenAddress),
|
|
2726
2728
|
amount,
|
|
2729
|
+
BigInt(params.deadline),
|
|
2727
2730
|
ensure0x(params.backendSignature),
|
|
2728
2731
|
],
|
|
2729
2732
|
});
|
|
@@ -2734,7 +2737,7 @@ class ContractService {
|
|
|
2734
2737
|
data,
|
|
2735
2738
|
};
|
|
2736
2739
|
if (isNative)
|
|
2737
|
-
txParams["value"] = `0x${amount.toString(16)}`;
|
|
2740
|
+
txParams["value"] = `0x${(amount + (amount * 50n) / 10000n).toString(16)}`;
|
|
2738
2741
|
let txHash;
|
|
2739
2742
|
try {
|
|
2740
2743
|
txHash = (await this.provider.request({
|
|
@@ -2803,8 +2806,8 @@ class PaymentService {
|
|
|
2803
2806
|
throw new KwesPayError(`Wallet is on chain ${confirmed} but payment requires chain ${expectedChainId} (${expectedNetwork}). Please switch your network and retry.`, "WRONG_NETWORK");
|
|
2804
2807
|
}
|
|
2805
2808
|
}
|
|
2806
|
-
async ensureSufficientBalance(walletAddress, tokenAddress,
|
|
2807
|
-
const
|
|
2809
|
+
async ensureSufficientBalance(walletAddress, tokenAddress, totalBaseUnits, onStatus) {
|
|
2810
|
+
const total = BigInt(totalBaseUnits);
|
|
2808
2811
|
const isNative = tokenAddress === ZERO_ADDRESS;
|
|
2809
2812
|
onStatus?.("Checking balance", "Verifying wallet balance…");
|
|
2810
2813
|
const nativeRaw = (await this.provider.request({
|
|
@@ -2813,14 +2816,14 @@ class PaymentService {
|
|
|
2813
2816
|
}));
|
|
2814
2817
|
const nativeBalance = nativeRaw && nativeRaw !== "0x" ? BigInt(nativeRaw) : 0n;
|
|
2815
2818
|
if (isNative) {
|
|
2816
|
-
const required =
|
|
2819
|
+
const required = total + GAS_BUFFER;
|
|
2817
2820
|
if (nativeBalance < required) {
|
|
2818
|
-
throw new KwesPayError(`Insufficient native balance. Required ~${(Number(required) / 1e18).toFixed(8)}
|
|
2821
|
+
throw new KwesPayError(`Insufficient native balance. Required ~${(Number(required) / 1e18).toFixed(8)} (payment + fee + gas), available: ${(Number(nativeBalance) / 1e18).toFixed(8)}.`, "INSUFFICIENT_BALANCE");
|
|
2819
2822
|
}
|
|
2820
2823
|
return;
|
|
2821
2824
|
}
|
|
2822
2825
|
if (nativeBalance < GAS_BUFFER) {
|
|
2823
|
-
throw new KwesPayError(`Insufficient gas balance. Need at least ${(Number(GAS_BUFFER) / 1e18).toFixed(8)}
|
|
2826
|
+
throw new KwesPayError(`Insufficient gas balance. Need at least ${(Number(GAS_BUFFER) / 1e18).toFixed(8)} for gas, available: ${(Number(nativeBalance) / 1e18).toFixed(8)}.`, "INSUFFICIENT_BALANCE");
|
|
2824
2827
|
}
|
|
2825
2828
|
const balanceData = "0x70a08231" + walletAddress.slice(2).toLowerCase().padStart(64, "0");
|
|
2826
2829
|
const raw = (await this.provider.request({
|
|
@@ -2828,33 +2831,44 @@ class PaymentService {
|
|
|
2828
2831
|
params: [{ to: tokenAddress, data: balanceData }, "latest"],
|
|
2829
2832
|
}));
|
|
2830
2833
|
const tokenBalance = raw && raw !== "0x" ? BigInt(raw) : 0n;
|
|
2831
|
-
if (tokenBalance <
|
|
2832
|
-
throw new KwesPayError(`Insufficient token balance. Required: ${
|
|
2834
|
+
if (tokenBalance < total) {
|
|
2835
|
+
throw new KwesPayError(`Insufficient token balance. Required: ${total.toString()} (amount + fee), available: ${tokenBalance.toString()} (base units).`, "INSUFFICIENT_BALANCE");
|
|
2833
2836
|
}
|
|
2834
2837
|
}
|
|
2835
2838
|
async pay(params) {
|
|
2836
|
-
const {
|
|
2839
|
+
const { payload, onStatus } = params;
|
|
2837
2840
|
if (!payload.paymentIdBytes32 || !payload.backendSignature) {
|
|
2838
2841
|
throw new KwesPayError("Invalid transaction payload — missing paymentIdBytes32 or backendSignature", "TRANSACTION_FAILED");
|
|
2839
2842
|
}
|
|
2840
2843
|
if (!payload.vendorIdentifier) {
|
|
2841
2844
|
throw new KwesPayError("Invalid transaction payload — missing vendorIdentifier", "TRANSACTION_FAILED");
|
|
2842
2845
|
}
|
|
2846
|
+
if (!payload.totalBaseUnits) {
|
|
2847
|
+
throw new KwesPayError("Invalid transaction payload — missing totalBaseUnits", "TRANSACTION_FAILED");
|
|
2848
|
+
}
|
|
2849
|
+
if (!payload.deadline) {
|
|
2850
|
+
throw new KwesPayError("Invalid transaction payload — missing deadline", "TRANSACTION_FAILED");
|
|
2851
|
+
}
|
|
2852
|
+
if (BigInt(payload.totalBaseUnits) < BigInt(payload.amountBaseUnits)) {
|
|
2853
|
+
throw new KwesPayError("Invalid transaction payload — totalBaseUnits cannot be less than amountBaseUnits", "TRANSACTION_FAILED");
|
|
2854
|
+
}
|
|
2843
2855
|
await this.ensureCorrectNetwork(payload.chainId, payload.network, onStatus);
|
|
2844
2856
|
const accounts = (await this.provider.request({
|
|
2845
2857
|
method: "eth_requestAccounts",
|
|
2846
2858
|
}));
|
|
2847
2859
|
const walletAddress = accounts[0];
|
|
2848
|
-
await this.ensureSufficientBalance(walletAddress, payload.tokenAddress, payload.
|
|
2860
|
+
await this.ensureSufficientBalance(walletAddress, payload.tokenAddress, payload.totalBaseUnits, onStatus);
|
|
2849
2861
|
const contractAddress = resolveContractAddress(payload.network);
|
|
2850
|
-
await this.contractService.ensureApproval(payload.tokenAddress, payload.
|
|
2862
|
+
await this.contractService.ensureApproval(payload.tokenAddress, payload.totalBaseUnits, contractAddress, payload.chainId, onStatus);
|
|
2851
2863
|
const { txHash, blockNumber } = await this.contractService.createPayment({
|
|
2852
2864
|
paymentIdBytes32: payload.paymentIdBytes32,
|
|
2853
2865
|
vendorIdentifier: payload.vendorIdentifier,
|
|
2854
2866
|
tokenAddress: payload.tokenAddress,
|
|
2855
2867
|
amountBaseUnits: payload.amountBaseUnits,
|
|
2868
|
+
totalBaseUnits: payload.totalBaseUnits,
|
|
2856
2869
|
backendSignature: payload.backendSignature,
|
|
2857
2870
|
contractAddress,
|
|
2871
|
+
deadline: payload.deadline,
|
|
2858
2872
|
chainId: payload.chainId,
|
|
2859
2873
|
}, onStatus);
|
|
2860
2874
|
return {
|
|
@@ -2866,6 +2880,14 @@ class PaymentService {
|
|
|
2866
2880
|
}
|
|
2867
2881
|
}
|
|
2868
2882
|
|
|
2883
|
+
const PLATFORM_FEE_BPS = 50n; // 0.5%
|
|
2884
|
+
const BASIS_POINTS = 10000n;
|
|
2885
|
+
function computeFee(amountBaseUnits) {
|
|
2886
|
+
return (BigInt(amountBaseUnits) * PLATFORM_FEE_BPS) / BASIS_POINTS;
|
|
2887
|
+
}
|
|
2888
|
+
function computeTotal(amountBaseUnits) {
|
|
2889
|
+
return (BigInt(amountBaseUnits) + computeFee(amountBaseUnits)).toString();
|
|
2890
|
+
}
|
|
2869
2891
|
class KwesPayClient {
|
|
2870
2892
|
constructor(config) {
|
|
2871
2893
|
if (!config.apiKey)
|
|
@@ -2897,6 +2919,7 @@ class KwesPayClient {
|
|
|
2897
2919
|
},
|
|
2898
2920
|
};
|
|
2899
2921
|
}
|
|
2922
|
+
// getQuote (price preview only — no transaction created)
|
|
2900
2923
|
async getQuote(params) {
|
|
2901
2924
|
const data = await gqlRequest(GQL_CREATE_QUOTE, {
|
|
2902
2925
|
input: {
|
|
@@ -2910,25 +2933,24 @@ class KwesPayClient {
|
|
|
2910
2933
|
const q = data.createQuote;
|
|
2911
2934
|
if (!q.success) {
|
|
2912
2935
|
const msg = q.message ?? "Quote creation failed";
|
|
2913
|
-
|
|
2914
|
-
? "QUOTE_EXPIRED"
|
|
2915
|
-
: msg.toLowerCase().includes("key")
|
|
2916
|
-
? "INVALID_KEY"
|
|
2917
|
-
: "UNKNOWN";
|
|
2918
|
-
throw new KwesPayError(msg, code);
|
|
2936
|
+
throw new KwesPayError(msg, _quoteErrCode(msg));
|
|
2919
2937
|
}
|
|
2920
2938
|
return {
|
|
2921
2939
|
quoteId: q.quoteId,
|
|
2922
2940
|
cryptoCurrency: q.cryptoCurrency,
|
|
2923
2941
|
tokenAddress: q.tokenAddress,
|
|
2924
2942
|
amountBaseUnits: q.amountBaseUnits,
|
|
2943
|
+
// totalBaseUnits = amountBaseUnits + fee — safe to compute here for UI
|
|
2944
|
+
totalBaseUnits: computeTotal(q.amountBaseUnits),
|
|
2925
2945
|
displayAmount: q.displayAmount,
|
|
2926
2946
|
network: q.network,
|
|
2927
2947
|
chainId: q.chainId,
|
|
2928
2948
|
expiresAt: q.expiresAt,
|
|
2929
2949
|
};
|
|
2930
2950
|
}
|
|
2951
|
+
// quote() — full flow: price + transaction, returns wallet-ready payload
|
|
2931
2952
|
async quote(params) {
|
|
2953
|
+
// Step 1 — get price & lock quote
|
|
2932
2954
|
const quoteData = await gqlRequest(GQL_CREATE_QUOTE, {
|
|
2933
2955
|
input: {
|
|
2934
2956
|
vendorIdentifier: params.vendorIdentifier,
|
|
@@ -2941,13 +2963,9 @@ class KwesPayClient {
|
|
|
2941
2963
|
const q = quoteData.createQuote;
|
|
2942
2964
|
if (!q.success) {
|
|
2943
2965
|
const msg = q.message ?? "Quote creation failed";
|
|
2944
|
-
|
|
2945
|
-
? "QUOTE_EXPIRED"
|
|
2946
|
-
: msg.toLowerCase().includes("key")
|
|
2947
|
-
? "INVALID_KEY"
|
|
2948
|
-
: "UNKNOWN";
|
|
2949
|
-
throw new KwesPayError(msg, code);
|
|
2966
|
+
throw new KwesPayError(msg, _quoteErrCode(msg));
|
|
2950
2967
|
}
|
|
2968
|
+
// Step 2 — create transaction (backend signs payment params incl. deadline)
|
|
2951
2969
|
const txData = await gqlRequest(GQL_CREATE_TRANSACTION, {
|
|
2952
2970
|
input: {
|
|
2953
2971
|
quoteId: q.quoteId,
|
|
@@ -2957,23 +2975,27 @@ class KwesPayClient {
|
|
|
2957
2975
|
const t = txData.createTransaction;
|
|
2958
2976
|
if (!t.success) {
|
|
2959
2977
|
const msg = t.message ?? "Transaction creation failed";
|
|
2960
|
-
|
|
2961
|
-
|
|
2962
|
-
|
|
2963
|
-
|
|
2964
|
-
|
|
2965
|
-
? "QUOTE_NOT_FOUND"
|
|
2966
|
-
: msg.toLowerCase().includes("key")
|
|
2967
|
-
? "INVALID_KEY"
|
|
2968
|
-
: "UNKNOWN";
|
|
2969
|
-
throw new KwesPayError(msg, code);
|
|
2978
|
+
throw new KwesPayError(msg, _txErrCode(msg));
|
|
2979
|
+
}
|
|
2980
|
+
// deadline must be present — it's part of the on-chain signature
|
|
2981
|
+
if (!t.deadline) {
|
|
2982
|
+
throw new KwesPayError("Backend did not return a deadline. Cannot construct a valid payment.", "TRANSACTION_FAILED");
|
|
2970
2983
|
}
|
|
2984
|
+
// totalBaseUnits: what the customer must actually send (amount + fee).
|
|
2985
|
+
// We compute this from the signed amountBaseUnits using the same formula
|
|
2986
|
+
// the contract uses: (amount * 50) / 10000. We do NOT trust a
|
|
2987
|
+
// client-side totalBaseUnits for security — but computing it here is safe
|
|
2988
|
+
// because amountBaseUnits came from the backend-signed response.
|
|
2989
|
+
const amountBaseUnits = t.amountBaseUnits;
|
|
2990
|
+
const totalBaseUnits = computeTotal(amountBaseUnits);
|
|
2971
2991
|
return {
|
|
2972
2992
|
paymentIdBytes32: t.paymentIdBytes32,
|
|
2973
2993
|
backendSignature: t.backendSignature,
|
|
2974
2994
|
tokenAddress: t.tokenAddress,
|
|
2975
|
-
amountBaseUnits
|
|
2995
|
+
amountBaseUnits,
|
|
2996
|
+
totalBaseUnits,
|
|
2976
2997
|
chainId: t.chainId,
|
|
2998
|
+
deadline: t.deadline, // ← from backend, part of signed hash
|
|
2977
2999
|
expiresAt: t.expiresAt,
|
|
2978
3000
|
transactionReference: t.transaction.transactionReference,
|
|
2979
3001
|
transactionStatus: t.transaction.transactionStatus,
|
|
@@ -2981,13 +3003,13 @@ class KwesPayClient {
|
|
|
2981
3003
|
vendorIdentifier: params.vendorIdentifier,
|
|
2982
3004
|
};
|
|
2983
3005
|
}
|
|
3006
|
+
// pay()
|
|
2984
3007
|
async pay(params) {
|
|
2985
3008
|
return new PaymentService(params.provider).pay(params);
|
|
2986
3009
|
}
|
|
3010
|
+
// status polling
|
|
2987
3011
|
async getTransactionStatus(transactionReference) {
|
|
2988
|
-
const data = await gqlRequest(GQL_TRANSACTION_STATUS, {
|
|
2989
|
-
transactionReference,
|
|
2990
|
-
});
|
|
3012
|
+
const data = await gqlRequest(GQL_TRANSACTION_STATUS, { transactionReference });
|
|
2991
3013
|
const r = data.getTransactionStatus;
|
|
2992
3014
|
return {
|
|
2993
3015
|
transactionReference: r.transactionReference,
|
|
@@ -3036,5 +3058,26 @@ class KwesPayClient {
|
|
|
3036
3058
|
});
|
|
3037
3059
|
}
|
|
3038
3060
|
}
|
|
3061
|
+
// Error code helpers
|
|
3062
|
+
function _quoteErrCode(msg) {
|
|
3063
|
+
const m = msg.toLowerCase();
|
|
3064
|
+
if (m.includes("expired"))
|
|
3065
|
+
return "QUOTE_EXPIRED";
|
|
3066
|
+
if (m.includes("key"))
|
|
3067
|
+
return "INVALID_KEY";
|
|
3068
|
+
return "UNKNOWN";
|
|
3069
|
+
}
|
|
3070
|
+
function _txErrCode(msg) {
|
|
3071
|
+
const m = msg.toLowerCase();
|
|
3072
|
+
if (m.includes("expired"))
|
|
3073
|
+
return "QUOTE_EXPIRED";
|
|
3074
|
+
if (m.includes("already been used"))
|
|
3075
|
+
return "QUOTE_USED";
|
|
3076
|
+
if (m.includes("not found"))
|
|
3077
|
+
return "QUOTE_NOT_FOUND";
|
|
3078
|
+
if (m.includes("key"))
|
|
3079
|
+
return "INVALID_KEY";
|
|
3080
|
+
return "UNKNOWN";
|
|
3081
|
+
}
|
|
3039
3082
|
|
|
3040
3083
|
export { KwesPayClient, KwesPayError };
|