nara-sdk 1.0.81 → 1.0.83
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/package.json +1 -1
- package/src/bridge.ts +38 -6
package/package.json
CHANGED
package/src/bridge.ts
CHANGED
|
@@ -49,6 +49,10 @@ export interface BridgeTokenSide {
|
|
|
49
49
|
export interface BridgeTokenConfig {
|
|
50
50
|
symbol: string;
|
|
51
51
|
decimals: number;
|
|
52
|
+
/** Minimum per-transfer amount in raw units (rejected if below) */
|
|
53
|
+
minAmount: bigint;
|
|
54
|
+
/** Minimum fee floor in raw units (fee = max(amount * bps, minFee)) */
|
|
55
|
+
minFee: bigint;
|
|
52
56
|
solana: BridgeTokenSide;
|
|
53
57
|
nara: BridgeTokenSide;
|
|
54
58
|
}
|
|
@@ -128,6 +132,8 @@ export const BRIDGE_TOKENS: Record<string, BridgeTokenConfig> = {
|
|
|
128
132
|
USDC: {
|
|
129
133
|
symbol: "USDC",
|
|
130
134
|
decimals: 6,
|
|
135
|
+
minAmount: 5_000_000n, // 5 USDC
|
|
136
|
+
minFee: 500_000n, // 0.5 USDC (fee floor)
|
|
131
137
|
solana: {
|
|
132
138
|
warpProgram: new PublicKey("4GcZJTa8s9vxtTz97Vj1RrwKMqPkT3DiiJkvUQDwsuZP"),
|
|
133
139
|
mode: "collateral",
|
|
@@ -144,6 +150,8 @@ export const BRIDGE_TOKENS: Record<string, BridgeTokenConfig> = {
|
|
|
144
150
|
USDT: {
|
|
145
151
|
symbol: "USDT",
|
|
146
152
|
decimals: 6,
|
|
153
|
+
minAmount: 5_000_000n, // 5 USDT
|
|
154
|
+
minFee: 500_000n, // 0.5 USDT (fee floor)
|
|
147
155
|
solana: {
|
|
148
156
|
warpProgram: new PublicKey("DCTt9H3pwwU89qC3Z4voYNThZypV68AwhYNzMNBxWXoy"),
|
|
149
157
|
mode: "collateral",
|
|
@@ -160,6 +168,8 @@ export const BRIDGE_TOKENS: Record<string, BridgeTokenConfig> = {
|
|
|
160
168
|
SOL: {
|
|
161
169
|
symbol: "SOL",
|
|
162
170
|
decimals: 9,
|
|
171
|
+
minAmount: 100_000_000n, // 0.1 SOL
|
|
172
|
+
minFee: 10_000_000n, // 0.01 SOL (fee floor)
|
|
163
173
|
solana: {
|
|
164
174
|
warpProgram: new PublicKey("46MmAWwKRAt9uvn7m44NXbVq2DCWBQE2r1TDw25nyXrt"),
|
|
165
175
|
mode: "native",
|
|
@@ -321,19 +331,32 @@ export function encodeTransferRemote(
|
|
|
321
331
|
// ─── Fee calculation ──────────────────────────────────────────────
|
|
322
332
|
|
|
323
333
|
export interface FeeSplit {
|
|
334
|
+
/** Total fee (max of percentage and minFee) in raw units */
|
|
324
335
|
feeAmount: bigint;
|
|
336
|
+
/** Net amount bridged after fee */
|
|
325
337
|
bridgeAmount: bigint;
|
|
338
|
+
/** Percentage part (bps) used */
|
|
326
339
|
feeBps: number;
|
|
340
|
+
/** Fee floor in raw units */
|
|
341
|
+
minFee: bigint;
|
|
327
342
|
}
|
|
328
343
|
|
|
329
|
-
|
|
344
|
+
/**
|
|
345
|
+
* Calculate the bridge fee: max(amount * bps / 10000, minFee)
|
|
346
|
+
*/
|
|
347
|
+
export function calculateBridgeFee(
|
|
348
|
+
amount: bigint,
|
|
349
|
+
feeBps?: number,
|
|
350
|
+
minFee: bigint = 0n
|
|
351
|
+
): FeeSplit {
|
|
330
352
|
const bps = feeBps ?? DEFAULT_BRIDGE_FEE_BPS;
|
|
331
353
|
if (bps < 0 || bps > BRIDGE_FEE_BPS_DENOMINATOR) {
|
|
332
354
|
throw new Error(`Invalid feeBps: ${bps}`);
|
|
333
355
|
}
|
|
334
|
-
const
|
|
356
|
+
const pctFee = (amount * BigInt(bps)) / BigInt(BRIDGE_FEE_BPS_DENOMINATOR);
|
|
357
|
+
const feeAmount = pctFee > minFee ? pctFee : minFee;
|
|
335
358
|
const bridgeAmount = amount - feeAmount;
|
|
336
|
-
return { feeAmount, bridgeAmount, feeBps: bps };
|
|
359
|
+
return { feeAmount, bridgeAmount, feeBps: bps, minFee };
|
|
337
360
|
}
|
|
338
361
|
|
|
339
362
|
// ─── Fee instruction builder ──────────────────────────────────────
|
|
@@ -523,12 +546,21 @@ export function makeBridgeIxs(params: BridgeTransferParams): BridgeIxsResult {
|
|
|
523
546
|
|
|
524
547
|
if (amount <= 0n) throw new Error("amount must be > 0");
|
|
525
548
|
|
|
549
|
+
// Enforce per-token minimum transfer amount
|
|
550
|
+
const tokenCfg = getToken(token);
|
|
551
|
+
if (amount < tokenCfg.minAmount) {
|
|
552
|
+
const min = Number(tokenCfg.minAmount) / Math.pow(10, tokenCfg.decimals);
|
|
553
|
+
throw new Error(
|
|
554
|
+
`Bridge amount too small: minimum for ${token} is ${min} (raw ${tokenCfg.minAmount})`
|
|
555
|
+
);
|
|
556
|
+
}
|
|
557
|
+
|
|
526
558
|
const split = skipFee
|
|
527
|
-
? { feeAmount: 0n, bridgeAmount: amount, feeBps: 0 }
|
|
528
|
-
: calculateBridgeFee(amount, feeBps);
|
|
559
|
+
? { feeAmount: 0n, bridgeAmount: amount, feeBps: 0, minFee: 0n }
|
|
560
|
+
: calculateBridgeFee(amount, feeBps, tokenCfg.minFee);
|
|
529
561
|
|
|
530
562
|
if (split.bridgeAmount <= 0n) {
|
|
531
|
-
throw new Error("bridge amount after fee is zero — increase amount or lower
|
|
563
|
+
throw new Error("bridge amount after fee is zero — increase amount or lower fee");
|
|
532
564
|
}
|
|
533
565
|
|
|
534
566
|
const recipientForFee = feeRecipient ?? getBridgeFeeRecipient(fromChain);
|