@flashnet/sdk 0.4.2 → 0.4.4
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/cjs/src/client/FlashnetClient.d.ts +1 -2
- package/dist/cjs/src/client/FlashnetClient.d.ts.map +1 -1
- package/dist/cjs/src/client/FlashnetClient.js +149 -31
- package/dist/cjs/src/client/FlashnetClient.js.map +1 -1
- package/dist/cjs/src/utils/auth.d.ts.map +1 -1
- package/dist/cjs/src/utils/auth.js +6 -1
- package/dist/cjs/src/utils/auth.js.map +1 -1
- package/dist/cjs/src/utils/crypto.d.ts +7 -0
- package/dist/cjs/src/utils/crypto.d.ts.map +1 -0
- package/dist/cjs/src/utils/hex.d.ts.map +1 -1
- package/dist/cjs/src/utils/hex.js +7 -3
- package/dist/cjs/src/utils/hex.js.map +1 -1
- package/dist/cjs/src/utils/index.js +1 -1
- package/dist/esm/src/client/FlashnetClient.d.ts +1 -2
- package/dist/esm/src/client/FlashnetClient.d.ts.map +1 -1
- package/dist/esm/src/client/FlashnetClient.js +145 -31
- package/dist/esm/src/client/FlashnetClient.js.map +1 -1
- package/dist/esm/src/utils/auth.d.ts.map +1 -1
- package/dist/esm/src/utils/auth.js +2 -1
- package/dist/esm/src/utils/auth.js.map +1 -1
- package/dist/esm/src/utils/crypto.d.ts +7 -0
- package/dist/esm/src/utils/crypto.d.ts.map +1 -0
- package/dist/esm/src/utils/hex.d.ts.map +1 -1
- package/dist/esm/src/utils/hex.js +7 -3
- package/dist/esm/src/utils/hex.js.map +1 -1
- package/dist/esm/src/utils/index.js +1 -1
- package/package.json +9 -5
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import sha256 from 'fast-sha256';
|
|
1
2
|
import { ApiClient } from '../api/client.js';
|
|
2
3
|
import { TypedAmmApi } from '../api/typed-endpoints.js';
|
|
3
4
|
import { getClientEnvironmentName, resolveClientNetworkConfig, getClientNetworkConfig, BTC_ASSET_PUBKEY } from '../config/index.js';
|
|
@@ -213,8 +214,7 @@ class FlashnetClient {
|
|
|
213
214
|
}
|
|
214
215
|
/**
|
|
215
216
|
* Convert a token identifier into the raw hex string form expected by the Flashnet backend.
|
|
216
|
-
*
|
|
217
|
-
* If it is in Bech32m human-readable form, it is decoded to hex.
|
|
217
|
+
* Handles BTC constant, hex strings, and Bech32m human-readable format.
|
|
218
218
|
*/
|
|
219
219
|
toHexTokenIdentifier(tokenIdentifier) {
|
|
220
220
|
if (tokenIdentifier === BTC_ASSET_PUBKEY) {
|
|
@@ -364,7 +364,7 @@ class FlashnetClient {
|
|
|
364
364
|
nonce,
|
|
365
365
|
});
|
|
366
366
|
// Sign intent
|
|
367
|
-
const messageHash =
|
|
367
|
+
const messageHash = sha256(intentMessage);
|
|
368
368
|
const signature = await this._wallet.config.signer.signMessageWithIdentityKey(messageHash, true);
|
|
369
369
|
// Create pool
|
|
370
370
|
const request = {
|
|
@@ -495,7 +495,7 @@ class FlashnetClient {
|
|
|
495
495
|
totalHostFeeRateBps: params.totalHostFeeRateBps.toString(),
|
|
496
496
|
nonce,
|
|
497
497
|
});
|
|
498
|
-
const messageHash =
|
|
498
|
+
const messageHash = sha256(intentMessage);
|
|
499
499
|
const signature = await this._wallet.config.signer.signMessageWithIdentityKey(messageHash, true);
|
|
500
500
|
// Create pool
|
|
501
501
|
const request = {
|
|
@@ -551,7 +551,7 @@ class FlashnetClient {
|
|
|
551
551
|
assetASparkTransferId,
|
|
552
552
|
nonce,
|
|
553
553
|
});
|
|
554
|
-
const messageHash =
|
|
554
|
+
const messageHash = sha256(intentMessage);
|
|
555
555
|
const signature = await this._wallet.config.signer.signMessageWithIdentityKey(messageHash, true);
|
|
556
556
|
const request = {
|
|
557
557
|
poolId,
|
|
@@ -635,7 +635,7 @@ class FlashnetClient {
|
|
|
635
635
|
nonce,
|
|
636
636
|
});
|
|
637
637
|
// Sign intent
|
|
638
|
-
const messageHash =
|
|
638
|
+
const messageHash = sha256(intentMessage);
|
|
639
639
|
const signature = await this._wallet.config.signer.signMessageWithIdentityKey(messageHash, true);
|
|
640
640
|
const request = {
|
|
641
641
|
userPublicKey: this.publicKey,
|
|
@@ -771,7 +771,7 @@ class FlashnetClient {
|
|
|
771
771
|
defaultIntegratorFeeRateBps: params.integratorFeeRateBps?.toString(),
|
|
772
772
|
});
|
|
773
773
|
// Sign intent
|
|
774
|
-
const messageHash =
|
|
774
|
+
const messageHash = sha256(intentMessage);
|
|
775
775
|
const signature = await this._wallet.config.signer.signMessageWithIdentityKey(messageHash, true);
|
|
776
776
|
const request = {
|
|
777
777
|
userPublicKey: this.publicKey,
|
|
@@ -870,7 +870,7 @@ class FlashnetClient {
|
|
|
870
870
|
nonce,
|
|
871
871
|
});
|
|
872
872
|
// Sign intent
|
|
873
|
-
const messageHash =
|
|
873
|
+
const messageHash = sha256(intentMessage);
|
|
874
874
|
const signature = await this._wallet.config.signer.signMessageWithIdentityKey(messageHash, true);
|
|
875
875
|
const request = {
|
|
876
876
|
userPublicKey: this.publicKey,
|
|
@@ -945,7 +945,7 @@ class FlashnetClient {
|
|
|
945
945
|
nonce,
|
|
946
946
|
});
|
|
947
947
|
// Sign intent
|
|
948
|
-
const messageHash =
|
|
948
|
+
const messageHash = sha256(intentMessage);
|
|
949
949
|
const signature = await this._wallet.config.signer.signMessageWithIdentityKey(messageHash, true);
|
|
950
950
|
const request = {
|
|
951
951
|
userPublicKey: this.publicKey,
|
|
@@ -979,7 +979,7 @@ class FlashnetClient {
|
|
|
979
979
|
nonce,
|
|
980
980
|
});
|
|
981
981
|
// Sign intent
|
|
982
|
-
const messageHash =
|
|
982
|
+
const messageHash = sha256(intentMessage);
|
|
983
983
|
const signature = await this._wallet.config.signer.signMessageWithIdentityKey(messageHash, true);
|
|
984
984
|
const request = {
|
|
985
985
|
namespace: params.namespace,
|
|
@@ -1027,7 +1027,7 @@ class FlashnetClient {
|
|
|
1027
1027
|
nonce,
|
|
1028
1028
|
});
|
|
1029
1029
|
// Sign intent
|
|
1030
|
-
const messageHash =
|
|
1030
|
+
const messageHash = sha256(intentMessage);
|
|
1031
1031
|
const signature = await this._wallet.config.signer.signMessageWithIdentityKey(messageHash, true);
|
|
1032
1032
|
const request = {
|
|
1033
1033
|
lpIdentityPublicKey: params.lpIdentityPublicKey,
|
|
@@ -1084,7 +1084,7 @@ class FlashnetClient {
|
|
|
1084
1084
|
nonce,
|
|
1085
1085
|
});
|
|
1086
1086
|
// Sign intent
|
|
1087
|
-
const messageHash =
|
|
1087
|
+
const messageHash = sha256(intentMessage);
|
|
1088
1088
|
const signature = await this._wallet.config.signer.signMessageWithIdentityKey(messageHash, true);
|
|
1089
1089
|
const request = {
|
|
1090
1090
|
integratorPublicKey: this.publicKey,
|
|
@@ -1135,7 +1135,7 @@ class FlashnetClient {
|
|
|
1135
1135
|
abandonConditions: params.abandonConditions || undefined,
|
|
1136
1136
|
nonce,
|
|
1137
1137
|
});
|
|
1138
|
-
const messageHash =
|
|
1138
|
+
const messageHash = sha256(intentMessage);
|
|
1139
1139
|
const signature = await this._wallet.config.signer.signMessageWithIdentityKey(messageHash, true);
|
|
1140
1140
|
const request = {
|
|
1141
1141
|
creatorPublicKey: this.publicKey,
|
|
@@ -1203,7 +1203,7 @@ class FlashnetClient {
|
|
|
1203
1203
|
nonce,
|
|
1204
1204
|
});
|
|
1205
1205
|
// Sign
|
|
1206
|
-
const messageHash =
|
|
1206
|
+
const messageHash = sha256(intentMessage);
|
|
1207
1207
|
const signature = await this._wallet.config.signer.signMessageWithIdentityKey(messageHash, true);
|
|
1208
1208
|
// Call API
|
|
1209
1209
|
const request = {
|
|
@@ -1228,7 +1228,7 @@ class FlashnetClient {
|
|
|
1228
1228
|
recipientPublicKey: this.publicKey,
|
|
1229
1229
|
nonce,
|
|
1230
1230
|
});
|
|
1231
|
-
const messageHash =
|
|
1231
|
+
const messageHash = sha256(intentMessage);
|
|
1232
1232
|
const signature = await this._wallet.config.signer.signMessageWithIdentityKey(messageHash, true);
|
|
1233
1233
|
const request = {
|
|
1234
1234
|
escrowId: params.escrowId,
|
|
@@ -1284,7 +1284,7 @@ class FlashnetClient {
|
|
|
1284
1284
|
lpIdentityPublicKey: params.lpIdentityPublicKey,
|
|
1285
1285
|
nonce,
|
|
1286
1286
|
});
|
|
1287
|
-
const messageHash =
|
|
1287
|
+
const messageHash = sha256(intentMessage);
|
|
1288
1288
|
const signature = await this._wallet.config.signer.signMessageWithIdentityKey(messageHash, true);
|
|
1289
1289
|
const request = {
|
|
1290
1290
|
senderPublicKey: this.publicKey,
|
|
@@ -1765,7 +1765,7 @@ class FlashnetClient {
|
|
|
1765
1765
|
assetBMinAmountIn: assetBMinAmountIn.toString(),
|
|
1766
1766
|
nonce,
|
|
1767
1767
|
});
|
|
1768
|
-
const messageHash =
|
|
1768
|
+
const messageHash = sha256(intentMessage);
|
|
1769
1769
|
const signature = await this._wallet.config.signer.signMessageWithIdentityKey(messageHash, true);
|
|
1770
1770
|
const request = {
|
|
1771
1771
|
userPublicKey: this.publicKey,
|
|
@@ -1802,7 +1802,18 @@ class FlashnetClient {
|
|
|
1802
1802
|
// Decode the invoice to get the amount
|
|
1803
1803
|
const invoiceAmountSats = await this.decodeInvoiceAmount(invoice);
|
|
1804
1804
|
if (!invoiceAmountSats || invoiceAmountSats <= 0) {
|
|
1805
|
-
throw new
|
|
1805
|
+
throw new FlashnetError("Unable to decode invoice amount. Zero-amount invoices are not supported for token payments.", {
|
|
1806
|
+
response: {
|
|
1807
|
+
errorCode: "FSAG-1002",
|
|
1808
|
+
errorCategory: "Validation",
|
|
1809
|
+
message: "Unable to decode invoice amount. Zero-amount invoices are not supported for token payments.",
|
|
1810
|
+
requestId: "",
|
|
1811
|
+
timestamp: new Date().toISOString(),
|
|
1812
|
+
service: "sdk",
|
|
1813
|
+
severity: "Error",
|
|
1814
|
+
remediation: "Provide a valid BOLT11 invoice with a non-zero amount.",
|
|
1815
|
+
},
|
|
1816
|
+
});
|
|
1806
1817
|
}
|
|
1807
1818
|
// Get Lightning fee estimate
|
|
1808
1819
|
const lightningFeeEstimate = await this.getLightningFeeEstimate(invoice);
|
|
@@ -1821,9 +1832,19 @@ class FlashnetClient {
|
|
|
1821
1832
|
// Check BTC minimum (output from swap)
|
|
1822
1833
|
const btcMinAmount = minAmounts.get(BTC_ASSET_PUBKEY.toLowerCase());
|
|
1823
1834
|
if (btcMinAmount && totalBtcNeeded < btcMinAmount) {
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1835
|
+
const msg = `Invoice amount too small. Minimum BTC output is ${btcMinAmount} sats, but invoice + lightning fee totals only ${totalBtcNeeded} sats.`;
|
|
1836
|
+
throw new FlashnetError(msg, {
|
|
1837
|
+
response: {
|
|
1838
|
+
errorCode: "FSAG-1003",
|
|
1839
|
+
errorCategory: "Validation",
|
|
1840
|
+
message: msg,
|
|
1841
|
+
requestId: "",
|
|
1842
|
+
timestamp: new Date().toISOString(),
|
|
1843
|
+
service: "sdk",
|
|
1844
|
+
severity: "Error",
|
|
1845
|
+
remediation: `Use an invoice of at least ${btcMinAmount} sats.`,
|
|
1846
|
+
},
|
|
1847
|
+
});
|
|
1827
1848
|
}
|
|
1828
1849
|
// Find the best pool to swap token -> BTC
|
|
1829
1850
|
const poolQuote = await this.findBestPoolForTokenToBtc(tokenAddress, totalBtcNeeded.toString(), options?.integratorFeeRateBps);
|
|
@@ -1832,9 +1853,19 @@ class FlashnetClient {
|
|
|
1832
1853
|
const tokenMinAmount = minAmounts.get(tokenHex);
|
|
1833
1854
|
if (tokenMinAmount &&
|
|
1834
1855
|
BigInt(poolQuote.tokenAmountRequired) < tokenMinAmount) {
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1856
|
+
const msg = `Token amount too small. Minimum input is ${tokenMinAmount} units, but calculated amount is only ${poolQuote.tokenAmountRequired} units.`;
|
|
1857
|
+
throw new FlashnetError(msg, {
|
|
1858
|
+
response: {
|
|
1859
|
+
errorCode: "FSAG-1003",
|
|
1860
|
+
errorCategory: "Validation",
|
|
1861
|
+
message: msg,
|
|
1862
|
+
requestId: "",
|
|
1863
|
+
timestamp: new Date().toISOString(),
|
|
1864
|
+
service: "sdk",
|
|
1865
|
+
severity: "Error",
|
|
1866
|
+
remediation: "Use a larger invoice amount.",
|
|
1867
|
+
},
|
|
1868
|
+
});
|
|
1838
1869
|
}
|
|
1839
1870
|
// Calculate the BTC variable fee adjustment (how much extra we're requesting)
|
|
1840
1871
|
const btcVariableFeeAdjustment = Number(totalBtcNeeded - baseBtcNeeded);
|
|
@@ -2068,6 +2099,8 @@ class FlashnetClient {
|
|
|
2068
2099
|
const tokenHex = this.toHexTokenIdentifier(tokenAddress);
|
|
2069
2100
|
const btcHex = BTC_ASSET_PUBKEY;
|
|
2070
2101
|
// Find all pools that have this token paired with BTC
|
|
2102
|
+
// Note: The API may return the same pool for both filter combinations,
|
|
2103
|
+
// so we need to deduplicate and determine tokenIsAssetA from actual pool data
|
|
2071
2104
|
const poolsWithTokenAsA = await this.listPools({
|
|
2072
2105
|
assetAAddress: tokenHex,
|
|
2073
2106
|
assetBAddress: btcHex,
|
|
@@ -2076,17 +2109,57 @@ class FlashnetClient {
|
|
|
2076
2109
|
assetAAddress: btcHex,
|
|
2077
2110
|
assetBAddress: tokenHex,
|
|
2078
2111
|
});
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2112
|
+
// Deduplicate pools by poolId and determine tokenIsAssetA from actual pool addresses
|
|
2113
|
+
const poolMap = new Map();
|
|
2114
|
+
for (const p of [...poolsWithTokenAsA.pools, ...poolsWithTokenAsB.pools]) {
|
|
2115
|
+
if (!poolMap.has(p.lpPublicKey)) {
|
|
2116
|
+
// Determine tokenIsAssetA from actual pool asset addresses, not from which query returned it
|
|
2117
|
+
const tokenIsAssetA = p.assetAAddress?.toLowerCase() === tokenHex.toLowerCase();
|
|
2118
|
+
poolMap.set(p.lpPublicKey, { pool: p, tokenIsAssetA });
|
|
2119
|
+
}
|
|
2120
|
+
}
|
|
2121
|
+
const allPools = Array.from(poolMap.values()).map(({ pool, tokenIsAssetA }) => ({
|
|
2122
|
+
...pool,
|
|
2123
|
+
tokenIsAssetA,
|
|
2124
|
+
}));
|
|
2083
2125
|
if (allPools.length === 0) {
|
|
2084
|
-
throw new
|
|
2126
|
+
throw new FlashnetError(`No liquidity pool found for token ${tokenAddress} paired with BTC`, {
|
|
2127
|
+
response: {
|
|
2128
|
+
errorCode: "FSAG-4001",
|
|
2129
|
+
errorCategory: "Business",
|
|
2130
|
+
message: `No liquidity pool found for token ${tokenAddress} paired with BTC`,
|
|
2131
|
+
requestId: "",
|
|
2132
|
+
timestamp: new Date().toISOString(),
|
|
2133
|
+
service: "sdk",
|
|
2134
|
+
severity: "Error",
|
|
2135
|
+
},
|
|
2136
|
+
});
|
|
2137
|
+
}
|
|
2138
|
+
// Pre-check: Get minimum amounts to provide clear error if invoice is too small
|
|
2139
|
+
const minAmounts = await this.getMinAmountsMap();
|
|
2140
|
+
const btcMinAmount = minAmounts.get(BTC_ASSET_PUBKEY.toLowerCase());
|
|
2141
|
+
// Check if the BTC amount needed is below the minimum
|
|
2142
|
+
if (btcMinAmount && BigInt(btcAmountNeeded) < btcMinAmount) {
|
|
2143
|
+
const msg = `Invoice amount too small. Minimum ${btcMinAmount} sats required, but invoice only requires ${btcAmountNeeded} sats.`;
|
|
2144
|
+
throw new FlashnetError(msg, {
|
|
2145
|
+
response: {
|
|
2146
|
+
errorCode: "FSAG-1003",
|
|
2147
|
+
errorCategory: "Validation",
|
|
2148
|
+
message: msg,
|
|
2149
|
+
requestId: "",
|
|
2150
|
+
timestamp: new Date().toISOString(),
|
|
2151
|
+
service: "sdk",
|
|
2152
|
+
severity: "Error",
|
|
2153
|
+
remediation: `Use an invoice with at least ${btcMinAmount} sats.`,
|
|
2154
|
+
},
|
|
2155
|
+
});
|
|
2085
2156
|
}
|
|
2086
2157
|
// Find the best pool (lowest token cost for the required BTC)
|
|
2087
2158
|
let bestPool = null;
|
|
2088
2159
|
let bestTokenAmount = BigInt(Number.MAX_SAFE_INTEGER);
|
|
2089
2160
|
let bestSimulation = null;
|
|
2161
|
+
// Track errors for each pool to provide better diagnostics
|
|
2162
|
+
const poolErrors = [];
|
|
2090
2163
|
for (const pool of allPools) {
|
|
2091
2164
|
try {
|
|
2092
2165
|
// Get pool details for reserves
|
|
@@ -2120,12 +2193,53 @@ class FlashnetClient {
|
|
|
2120
2193
|
warningMessage: simulation.warningMessage,
|
|
2121
2194
|
};
|
|
2122
2195
|
}
|
|
2196
|
+
else {
|
|
2197
|
+
// Simulation output was insufficient
|
|
2198
|
+
const btcReserve = pool.tokenIsAssetA
|
|
2199
|
+
? poolDetails.assetBReserve
|
|
2200
|
+
: poolDetails.assetAReserve;
|
|
2201
|
+
poolErrors.push({
|
|
2202
|
+
poolId: pool.lpPublicKey,
|
|
2203
|
+
error: `Simulation output (${simulation.amountOut} sats) < required (${btcAmountNeeded} sats)`,
|
|
2204
|
+
btcReserve,
|
|
2205
|
+
});
|
|
2206
|
+
}
|
|
2123
2207
|
}
|
|
2124
2208
|
}
|
|
2125
|
-
catch {
|
|
2209
|
+
catch (e) {
|
|
2210
|
+
// Capture pool errors for diagnostics
|
|
2211
|
+
const errorMessage = e instanceof Error ? e.message : String(e);
|
|
2212
|
+
poolErrors.push({
|
|
2213
|
+
poolId: pool.lpPublicKey,
|
|
2214
|
+
error: errorMessage,
|
|
2215
|
+
});
|
|
2216
|
+
}
|
|
2126
2217
|
}
|
|
2127
2218
|
if (!bestPool || !bestSimulation) {
|
|
2128
|
-
|
|
2219
|
+
let errorMessage = `No pool has sufficient liquidity for ${btcAmountNeeded} sats`;
|
|
2220
|
+
if (poolErrors.length > 0) {
|
|
2221
|
+
const details = poolErrors
|
|
2222
|
+
.map((pe) => {
|
|
2223
|
+
const reserveInfo = pe.btcReserve
|
|
2224
|
+
? ` (BTC reserve: ${pe.btcReserve})`
|
|
2225
|
+
: "";
|
|
2226
|
+
return ` - Pool ${pe.poolId.slice(0, 12)}...${reserveInfo}: ${pe.error}`;
|
|
2227
|
+
})
|
|
2228
|
+
.join("\n");
|
|
2229
|
+
errorMessage += `\n\nPool evaluation details:\n${details}`;
|
|
2230
|
+
}
|
|
2231
|
+
throw new FlashnetError(errorMessage, {
|
|
2232
|
+
response: {
|
|
2233
|
+
errorCode: "FSAG-4201",
|
|
2234
|
+
errorCategory: "Business",
|
|
2235
|
+
message: errorMessage,
|
|
2236
|
+
requestId: "",
|
|
2237
|
+
timestamp: new Date().toISOString(),
|
|
2238
|
+
service: "sdk",
|
|
2239
|
+
severity: "Error",
|
|
2240
|
+
remediation: "Try a smaller amount or wait for more liquidity.",
|
|
2241
|
+
},
|
|
2242
|
+
});
|
|
2129
2243
|
}
|
|
2130
2244
|
const poolDetails = await this.getPool(bestPool.lpPublicKey);
|
|
2131
2245
|
return {
|