@diviswap/sdk 1.9.1 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/index.js +69 -21
- package/dist/index.d.mts +10 -28
- package/dist/index.d.ts +10 -28
- package/dist/index.js +243 -48
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +243 -48
- package/dist/index.mjs.map +1 -1
- package/dist/react/index.d.mts +1 -1
- package/dist/react/index.d.ts +1 -1
- package/dist/{wallet-yDJlJqCw.d.mts → wallet-DO1Nbsfk.d.mts} +36 -5
- package/dist/{wallet-yDJlJqCw.d.ts → wallet-DO1Nbsfk.d.ts} +36 -5
- package/package.json +2 -1
package/dist/index.mjs
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { keccak_256 } from '@noble/hashes/sha3';
|
|
1
2
|
import crypto from 'crypto';
|
|
2
3
|
|
|
3
4
|
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
@@ -64,31 +65,43 @@ var AuthModule = class {
|
|
|
64
65
|
* ```
|
|
65
66
|
*/
|
|
66
67
|
async register(data) {
|
|
68
|
+
if (!data.email || !data.password) {
|
|
69
|
+
throw new ValidationError("Email and password are required");
|
|
70
|
+
}
|
|
71
|
+
if (!data.firstName || !data.lastName) {
|
|
72
|
+
throw new ValidationError("First name and last name are required for KYC compliance");
|
|
73
|
+
}
|
|
74
|
+
if (!data.individual) {
|
|
75
|
+
throw new ValidationError(
|
|
76
|
+
"Complete individual KYC information is required for registration. Please provide residential address, date of birth, and government ID information."
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
const individual = data.individual;
|
|
80
|
+
const requiredIndividualFields = [
|
|
81
|
+
"residential_country_code",
|
|
82
|
+
"residential_address_line_one",
|
|
83
|
+
"residential_city",
|
|
84
|
+
"residential_state",
|
|
85
|
+
"residential_postal_code",
|
|
86
|
+
"id_country_code",
|
|
87
|
+
"dob",
|
|
88
|
+
"id_number"
|
|
89
|
+
];
|
|
90
|
+
for (const field of requiredIndividualFields) {
|
|
91
|
+
const value = individual[field];
|
|
92
|
+
if (value === void 0 || value === null || value === "") {
|
|
93
|
+
throw new ValidationError(
|
|
94
|
+
`Missing required KYC field: ${field}. All identity information must be provided for compliance.`
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
67
98
|
const requestData = {
|
|
68
99
|
email: data.email,
|
|
69
100
|
password: data.password,
|
|
70
|
-
first_name: data.firstName
|
|
71
|
-
last_name: data.lastName
|
|
72
|
-
|
|
73
|
-
individual: {
|
|
74
|
-
// Use 'USA' (3-letter code) as seen in working lbx-landing implementation
|
|
75
|
-
residential_country_code: "USA",
|
|
76
|
-
residential_address_line_one: "123 Main Street",
|
|
77
|
-
residential_address_line_two: "",
|
|
78
|
-
residential_city: "Anytown",
|
|
79
|
-
residential_state: "CA",
|
|
80
|
-
residential_postal_code: "12345",
|
|
81
|
-
id_type: "ssn",
|
|
82
|
-
// Add id_type field as seen in lbx-landing
|
|
83
|
-
id_country_code: "USA",
|
|
84
|
-
dob: "1990-01-01",
|
|
85
|
-
id_number: "123456789"
|
|
86
|
-
// Remove dashes from SSN like lbx-landing does
|
|
87
|
-
}
|
|
101
|
+
first_name: data.firstName,
|
|
102
|
+
last_name: data.lastName,
|
|
103
|
+
individual: data.individual
|
|
88
104
|
};
|
|
89
|
-
if (data.individual) {
|
|
90
|
-
requestData.individual = data.individual;
|
|
91
|
-
}
|
|
92
105
|
if (data.phone) requestData.phone = data.phone;
|
|
93
106
|
if (data.referralCode) requestData.referral_code = data.referralCode;
|
|
94
107
|
const response = await this.client.post(
|
|
@@ -519,19 +532,116 @@ var STABLECOIN_ADDRESSES = {
|
|
|
519
532
|
// Wrapped SOL
|
|
520
533
|
}
|
|
521
534
|
};
|
|
535
|
+
function isValidEthereumAddress(address) {
|
|
536
|
+
if (!/^0x[0-9a-fA-F]{40}$/.test(address)) {
|
|
537
|
+
return false;
|
|
538
|
+
}
|
|
539
|
+
if (address === address.toLowerCase() || address === address.toUpperCase()) {
|
|
540
|
+
return true;
|
|
541
|
+
}
|
|
542
|
+
return address === toChecksumAddress(address);
|
|
543
|
+
}
|
|
544
|
+
function toChecksumAddress(address) {
|
|
545
|
+
if (!address.startsWith("0x")) {
|
|
546
|
+
throw new Error("Invalid Ethereum address: must start with 0x");
|
|
547
|
+
}
|
|
548
|
+
const lowerAddress = address.toLowerCase().replace("0x", "");
|
|
549
|
+
const hash = keccak256(lowerAddress);
|
|
550
|
+
let checksumAddress = "0x";
|
|
551
|
+
for (let i = 0; i < lowerAddress.length; i++) {
|
|
552
|
+
const hashByte = parseInt(hash[i], 16);
|
|
553
|
+
checksumAddress += hashByte >= 8 ? lowerAddress[i].toUpperCase() : lowerAddress[i];
|
|
554
|
+
}
|
|
555
|
+
return checksumAddress;
|
|
556
|
+
}
|
|
557
|
+
function keccak256(input) {
|
|
558
|
+
const bytes = new TextEncoder().encode(input);
|
|
559
|
+
const hash = keccak_256(bytes);
|
|
560
|
+
return Array.from(hash).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
561
|
+
}
|
|
562
|
+
function isValidSolanaAddress(address) {
|
|
563
|
+
const base58Regex = /^[1-9A-HJ-NP-Za-km-z]{32,44}$/;
|
|
564
|
+
if (!base58Regex.test(address)) {
|
|
565
|
+
return false;
|
|
566
|
+
}
|
|
567
|
+
if (/[0OIl]/.test(address)) {
|
|
568
|
+
return false;
|
|
569
|
+
}
|
|
570
|
+
return true;
|
|
571
|
+
}
|
|
572
|
+
function isValidBitcoinAddress(address) {
|
|
573
|
+
const legacyRegex = /^1[1-9A-HJ-NP-Za-km-z]{25,34}$/;
|
|
574
|
+
const segwitRegex = /^3[1-9A-HJ-NP-Za-km-z]{25,34}$/;
|
|
575
|
+
const bech32Regex = /^bc1[a-z0-9]{39,87}$/i;
|
|
576
|
+
return legacyRegex.test(address) || segwitRegex.test(address) || bech32Regex.test(address);
|
|
577
|
+
}
|
|
578
|
+
function isValidTronAddress(address) {
|
|
579
|
+
if (!address.startsWith("T") || address.length !== 34) {
|
|
580
|
+
return false;
|
|
581
|
+
}
|
|
582
|
+
const base58Regex = /^T[1-9A-HJ-NP-Za-km-z]{33}$/;
|
|
583
|
+
return base58Regex.test(address);
|
|
584
|
+
}
|
|
585
|
+
function isValidCryptoAddress(address, chain) {
|
|
586
|
+
const chainLower = chain.toLowerCase();
|
|
587
|
+
switch (chainLower) {
|
|
588
|
+
case "ethereum":
|
|
589
|
+
case "eth":
|
|
590
|
+
case "polygon":
|
|
591
|
+
case "matic":
|
|
592
|
+
case "arbitrum":
|
|
593
|
+
case "optimism":
|
|
594
|
+
case "base":
|
|
595
|
+
case "avalanche":
|
|
596
|
+
case "bsc":
|
|
597
|
+
case "binance":
|
|
598
|
+
return isValidEthereumAddress(address);
|
|
599
|
+
case "solana":
|
|
600
|
+
case "sol":
|
|
601
|
+
return isValidSolanaAddress(address);
|
|
602
|
+
case "bitcoin":
|
|
603
|
+
case "btc":
|
|
604
|
+
return isValidBitcoinAddress(address);
|
|
605
|
+
case "tron":
|
|
606
|
+
case "trx":
|
|
607
|
+
return isValidTronAddress(address);
|
|
608
|
+
default:
|
|
609
|
+
throw new Error(`Unsupported chain: ${chain}`);
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
function extractTransactionHash(result) {
|
|
613
|
+
if (typeof result === "string") {
|
|
614
|
+
return result;
|
|
615
|
+
}
|
|
616
|
+
if ("hash" in result && result.hash) {
|
|
617
|
+
return result.hash;
|
|
618
|
+
}
|
|
619
|
+
if ("transactionHash" in result && result.transactionHash) {
|
|
620
|
+
return result.transactionHash;
|
|
621
|
+
}
|
|
622
|
+
throw new Error(
|
|
623
|
+
'Unable to extract transaction hash from result. Expected string or object with "hash" or "transactionHash" property.'
|
|
624
|
+
);
|
|
625
|
+
}
|
|
522
626
|
|
|
523
627
|
// src/modules/transactions.ts
|
|
524
|
-
var
|
|
628
|
+
var _TransactionsModule = class _TransactionsModule {
|
|
525
629
|
constructor(client, environment = "sandbox") {
|
|
526
630
|
this.client = client;
|
|
527
631
|
this.depositAddresses = getDepositAddresses(environment);
|
|
528
632
|
}
|
|
529
633
|
/**
|
|
530
|
-
* Map chain name to chain ID
|
|
634
|
+
* Map chain name to chain ID with validation
|
|
531
635
|
* @private
|
|
532
636
|
*/
|
|
533
637
|
getChainId(chain) {
|
|
534
|
-
const
|
|
638
|
+
const chainLower = chain.toLowerCase();
|
|
639
|
+
if (!_TransactionsModule.SUPPORTED_CHAINS.includes(chainLower)) {
|
|
640
|
+
throw new ValidationError(
|
|
641
|
+
`Unsupported chain: ${chain}. Supported chains: ${_TransactionsModule.SUPPORTED_CHAINS.filter((c, i, arr) => arr.indexOf(c) === i).join(", ")}`
|
|
642
|
+
);
|
|
643
|
+
}
|
|
644
|
+
const chainId = CHAIN_NAME_TO_ID[chainLower];
|
|
535
645
|
return chainId ? chainId.toString() : chain;
|
|
536
646
|
}
|
|
537
647
|
/**
|
|
@@ -620,17 +730,30 @@ var TransactionsModule = class {
|
|
|
620
730
|
*/
|
|
621
731
|
async offramp(data) {
|
|
622
732
|
if (!data.txHash || data.txHash.trim() === "") {
|
|
623
|
-
throw new
|
|
733
|
+
throw new ValidationError("txHash is required for offramp transactions.");
|
|
734
|
+
}
|
|
735
|
+
const chain = data.chain || "ethereum";
|
|
736
|
+
const chainId = this.getChainId(chain);
|
|
737
|
+
if (!isValidCryptoAddress(data.fromAddress, chain)) {
|
|
738
|
+
throw new ValidationError(
|
|
739
|
+
`Invalid ${chain} address: ${data.fromAddress}. Please check the address format.`
|
|
740
|
+
);
|
|
741
|
+
}
|
|
742
|
+
const toAddress = data.toAddress || this.getDepositAddress(chain);
|
|
743
|
+
if (!isValidCryptoAddress(toAddress, chain)) {
|
|
744
|
+
throw new ValidationError(
|
|
745
|
+
`Invalid ${chain} deposit address: ${toAddress}. Please contact support.`
|
|
746
|
+
);
|
|
624
747
|
}
|
|
625
748
|
const payload = {
|
|
626
749
|
payee_id: data.payeeId,
|
|
627
750
|
tx_hash: data.txHash,
|
|
628
751
|
// Required: must send crypto first
|
|
629
752
|
from_address: data.fromAddress,
|
|
630
|
-
to_address:
|
|
753
|
+
to_address: toAddress,
|
|
631
754
|
amount: data.amount,
|
|
632
755
|
currency: data.currency,
|
|
633
|
-
chain_id:
|
|
756
|
+
chain_id: chainId
|
|
634
757
|
};
|
|
635
758
|
if (data.memo) {
|
|
636
759
|
payload.memo = data.memo;
|
|
@@ -818,6 +941,26 @@ var TransactionsModule = class {
|
|
|
818
941
|
return STABLECOIN_ADDRESSES[chainName] || {};
|
|
819
942
|
}
|
|
820
943
|
};
|
|
944
|
+
// Supported chains for validation
|
|
945
|
+
_TransactionsModule.SUPPORTED_CHAINS = [
|
|
946
|
+
"ethereum",
|
|
947
|
+
"eth",
|
|
948
|
+
"polygon",
|
|
949
|
+
"matic",
|
|
950
|
+
"arbitrum",
|
|
951
|
+
"optimism",
|
|
952
|
+
"base",
|
|
953
|
+
"avalanche",
|
|
954
|
+
"bsc",
|
|
955
|
+
"binance",
|
|
956
|
+
"solana",
|
|
957
|
+
"sol",
|
|
958
|
+
"bitcoin",
|
|
959
|
+
"btc",
|
|
960
|
+
"tron",
|
|
961
|
+
"trx"
|
|
962
|
+
];
|
|
963
|
+
var TransactionsModule = _TransactionsModule;
|
|
821
964
|
|
|
822
965
|
// src/modules/kyc.ts
|
|
823
966
|
var KycModule = class {
|
|
@@ -1533,8 +1676,8 @@ var MemoryTokenStorage = class {
|
|
|
1533
1676
|
}
|
|
1534
1677
|
};
|
|
1535
1678
|
var LocalStorageTokenStorage = class {
|
|
1536
|
-
constructor() {
|
|
1537
|
-
this.key = "liberex_tokens";
|
|
1679
|
+
constructor(userId) {
|
|
1680
|
+
this.key = userId ? `liberex_tokens_${userId}` : "liberex_tokens";
|
|
1538
1681
|
}
|
|
1539
1682
|
get() {
|
|
1540
1683
|
if (typeof globalThis.window === "undefined") return null;
|
|
@@ -1556,9 +1699,14 @@ var LocalStorageTokenStorage = class {
|
|
|
1556
1699
|
}
|
|
1557
1700
|
};
|
|
1558
1701
|
var TokenManager = class {
|
|
1559
|
-
|
|
1702
|
+
/**
|
|
1703
|
+
* Create a new TokenManager
|
|
1704
|
+
* @param useLocalStorage Whether to use localStorage (default: memory storage for security)
|
|
1705
|
+
* @param userId Optional user ID for multi-user session isolation
|
|
1706
|
+
*/
|
|
1707
|
+
constructor(useLocalStorage = false, userId) {
|
|
1560
1708
|
this.refreshPromise = null;
|
|
1561
|
-
this.storage = useLocalStorage && typeof globalThis.window !== "undefined" ? new LocalStorageTokenStorage() : new MemoryTokenStorage();
|
|
1709
|
+
this.storage = useLocalStorage && typeof globalThis.window !== "undefined" ? new LocalStorageTokenStorage(userId) : new MemoryTokenStorage();
|
|
1562
1710
|
}
|
|
1563
1711
|
/**
|
|
1564
1712
|
* Parse JWT token to extract expiration
|
|
@@ -1659,6 +1807,18 @@ var PartnerAuth = class {
|
|
|
1659
1807
|
constructor(credentials) {
|
|
1660
1808
|
this.credentials = credentials;
|
|
1661
1809
|
}
|
|
1810
|
+
/**
|
|
1811
|
+
* Override toJSON to prevent accidental serialization of secret key
|
|
1812
|
+
*/
|
|
1813
|
+
toJSON() {
|
|
1814
|
+
return {
|
|
1815
|
+
keyId: this.credentials.keyId,
|
|
1816
|
+
customerId: this.credentials.customerId,
|
|
1817
|
+
customerEmail: this.credentials.customerEmail,
|
|
1818
|
+
secretKey: "***REDACTED***"
|
|
1819
|
+
// Never expose secret key
|
|
1820
|
+
};
|
|
1821
|
+
}
|
|
1662
1822
|
/**
|
|
1663
1823
|
* Generate HMAC authentication headers for a request
|
|
1664
1824
|
*/
|
|
@@ -1750,17 +1910,54 @@ var PartnerAuth = class {
|
|
|
1750
1910
|
// src/api/unified-client.ts
|
|
1751
1911
|
var UnifiedApiClient = class _UnifiedApiClient {
|
|
1752
1912
|
constructor(config, useLocalStorage = true) {
|
|
1753
|
-
this
|
|
1913
|
+
Object.defineProperty(this, "_secureApiKey", {
|
|
1914
|
+
value: config.apiKey,
|
|
1915
|
+
writable: false,
|
|
1916
|
+
enumerable: false,
|
|
1917
|
+
configurable: false
|
|
1918
|
+
});
|
|
1919
|
+
Object.defineProperty(this, "_secureSecretKey", {
|
|
1920
|
+
value: config.secretKey,
|
|
1921
|
+
writable: false,
|
|
1922
|
+
enumerable: false,
|
|
1923
|
+
configurable: false
|
|
1924
|
+
});
|
|
1925
|
+
const { apiKey, secretKey, ...safeConfig } = config;
|
|
1926
|
+
this.config = safeConfig;
|
|
1754
1927
|
this.tokenManager = new TokenManager(useLocalStorage);
|
|
1755
|
-
|
|
1928
|
+
const secureSecretKey = this._secureSecretKey;
|
|
1929
|
+
if (config.mode === "partner" && config.keyId && secureSecretKey) {
|
|
1756
1930
|
this.partnerAuth = new PartnerAuth({
|
|
1757
1931
|
keyId: config.keyId,
|
|
1758
|
-
secretKey:
|
|
1932
|
+
secretKey: secureSecretKey,
|
|
1759
1933
|
customerId: config.customerId,
|
|
1760
1934
|
customerEmail: config.customerEmail
|
|
1761
1935
|
});
|
|
1762
1936
|
}
|
|
1763
1937
|
}
|
|
1938
|
+
/**
|
|
1939
|
+
* Override toJSON to prevent accidental serialization of sensitive data
|
|
1940
|
+
*/
|
|
1941
|
+
toJSON() {
|
|
1942
|
+
return {
|
|
1943
|
+
mode: this.config.mode,
|
|
1944
|
+
baseUrl: this.config.baseUrl,
|
|
1945
|
+
timeout: this.config.timeout,
|
|
1946
|
+
debug: this.config.debug,
|
|
1947
|
+
// Never expose credentials
|
|
1948
|
+
apiKey: this.config.apiKey ? "***REDACTED***" : void 0,
|
|
1949
|
+
secretKey: this.config.secretKey ? "***REDACTED***" : void 0,
|
|
1950
|
+
keyId: this.config.keyId,
|
|
1951
|
+
clientId: this.config.clientId
|
|
1952
|
+
};
|
|
1953
|
+
}
|
|
1954
|
+
/**
|
|
1955
|
+
* Get the actual API key (for internal use only)
|
|
1956
|
+
* @internal
|
|
1957
|
+
*/
|
|
1958
|
+
getApiKey() {
|
|
1959
|
+
return this._secureApiKey;
|
|
1960
|
+
}
|
|
1764
1961
|
/**
|
|
1765
1962
|
* Create client from legacy user config (backward compatibility)
|
|
1766
1963
|
*/
|
|
@@ -1908,7 +2105,15 @@ var UnifiedApiClient = class _UnifiedApiClient {
|
|
|
1908
2105
|
this.config.timeout
|
|
1909
2106
|
);
|
|
1910
2107
|
if (this.config.debug) {
|
|
1911
|
-
|
|
2108
|
+
const safeHeaders = { ...requestHeaders };
|
|
2109
|
+
if (safeHeaders["X-API-Key"]) safeHeaders["X-API-Key"] = "***REDACTED***";
|
|
2110
|
+
if (safeHeaders["Authorization"]?.startsWith("Bearer ")) {
|
|
2111
|
+
safeHeaders["Authorization"] = "Bearer ***REDACTED***";
|
|
2112
|
+
}
|
|
2113
|
+
if (safeHeaders["Authorization"]?.startsWith("HMAC ")) {
|
|
2114
|
+
safeHeaders["Authorization"] = "HMAC ***REDACTED***";
|
|
2115
|
+
}
|
|
2116
|
+
console.log(`[Diviswap SDK] ${method} ${url}`, { headers: safeHeaders });
|
|
1912
2117
|
}
|
|
1913
2118
|
const response = await fetch(url, {
|
|
1914
2119
|
method,
|
|
@@ -1976,12 +2181,13 @@ var UnifiedApiClient = class _UnifiedApiClient {
|
|
|
1976
2181
|
* Add user authentication headers (legacy)
|
|
1977
2182
|
*/
|
|
1978
2183
|
async addUserAuth(useApiKey, headers) {
|
|
1979
|
-
|
|
2184
|
+
const apiKey = this.getApiKey();
|
|
2185
|
+
if (!apiKey || !this.config.clientId) {
|
|
1980
2186
|
throw new AuthenticationError("User authentication not configured");
|
|
1981
2187
|
}
|
|
1982
2188
|
headers["X-CLIENT-ID"] = this.config.clientId;
|
|
1983
2189
|
headers["X-TIMESTAMP"] = Math.floor(Date.now() / 1e3).toString();
|
|
1984
|
-
headers["X-API-Key"] =
|
|
2190
|
+
headers["X-API-Key"] = apiKey;
|
|
1985
2191
|
if (!useApiKey) {
|
|
1986
2192
|
const accessToken = await this.tokenManager.getValidAccessToken(
|
|
1987
2193
|
this.refreshCallback
|
|
@@ -2417,17 +2623,6 @@ function setupWalletTracking(diviswap, wallet, config) {
|
|
|
2417
2623
|
return tracker;
|
|
2418
2624
|
}
|
|
2419
2625
|
|
|
2420
|
-
// src/utils/web3.ts
|
|
2421
|
-
function extractTransactionHash(result) {
|
|
2422
|
-
if (typeof result === "string") {
|
|
2423
|
-
return result;
|
|
2424
|
-
}
|
|
2425
|
-
if (typeof result === "object" && result !== null && "hash" in result) {
|
|
2426
|
-
return result.hash;
|
|
2427
|
-
}
|
|
2428
|
-
return result;
|
|
2429
|
-
}
|
|
2430
|
-
|
|
2431
2626
|
export { AuthenticationError, CHAIN_IDS, CHAIN_ID_TO_NAME, CHAIN_NAME_TO_ID, ConfigurationError, Diviswap, DiviswapError, Diviswap as LiberEx, LiberExError, NetworkError, PRODUCTION_DEPOSIT_ADDRESSES, SANDBOX_DEPOSIT_ADDRESSES, STABLECOIN_ADDRESSES, ValidationError, WalletTracker, connectWallet, extractTransactionHash, getDepositAddresses, setupWalletTracking, trackCurrentWallet };
|
|
2432
2627
|
//# sourceMappingURL=index.mjs.map
|
|
2433
2628
|
//# sourceMappingURL=index.mjs.map
|