Skip to content

Commit 208ec2c

Browse files
committed
feat(pricing): add sign-session-key pricing support and product-aware sorting
- request `SIGN_SESSION_KEY` prices when fetching node data so the contract returns all four product columns - extend pricing context schema to accept `SIGN_SESSION_KEY` and re-sort nodes per product before slicing to threshold - route PKP auth through `SIGN_SESSION_KEY` pricing while keeping custom auth on `LIT_ACTION` - cover the new sort logic with a unit test to prove we now pick the cheapest validators for the requested product
1 parent 35da202 commit 208ec2c

File tree

5 files changed

+80
-5
lines changed

5 files changed

+80
-5
lines changed

packages/auth/src/lib/AuthManager/authAdapters/getPkpAuthContextAdapter.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,9 +136,9 @@ export async function getPkpAuthContextAdapter(
136136
const nodeUrls = litClientCtx.getMaxPricesForNodeProduct({
137137
nodePrices: nodePrices,
138138
userMaxPrice: litClientCtx.getUserMaxPrice({
139-
product: 'LIT_ACTION',
139+
product: 'SIGN_SESSION_KEY',
140140
}),
141-
productId: PRODUCT_IDS['LIT_ACTION'],
141+
productId: PRODUCT_IDS['SIGN_SESSION_KEY'],
142142
numRequiredNodes: threshold,
143143
});
144144

packages/networks/src/networks/vNaga/shared/managers/LitChainClient/apis/rawContractApis/pricing/getNodesForRequest.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {
1515
* - DECRYPTION (0): Used for decryption operations
1616
* - SIGN (1): Used for signing operations
1717
* - LA (2): Used for Lit Actions execution
18+
* - SIGN_SESSION_KEY (3): Used for sign session key operations
1819
*/
1920
export const PRODUCT_IDS = {
2021
DECRYPTION: 0n, // For decryption operations
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import { PRODUCT_IDS } from '@lit-protocol/constants';
2+
3+
import { getMaxPricesForNodeProduct } from './getMaxPricesForNodeProduct';
4+
5+
describe('getMaxPricesForNodeProduct', () => {
6+
it('uses the requested product column when ranking nodes', () => {
7+
const nodePrices = [
8+
{
9+
url: 'https://node-a',
10+
prices: [80n, 5n, 9n, 30n],
11+
},
12+
{
13+
url: 'https://node-b',
14+
prices: [70n, 4n, 8n, 10n],
15+
},
16+
{
17+
url: 'https://node-c',
18+
prices: [60n, 3n, 7n, 20n],
19+
},
20+
];
21+
22+
// Log the incoming order to show the encryption column is already sorted lowest-first.
23+
console.log(
24+
'incoming order',
25+
nodePrices.map(({ url, prices }) => ({
26+
url,
27+
decryptionPrice: prices[PRODUCT_IDS.DECRYPTION],
28+
signPrice: prices[PRODUCT_IDS.SIGN],
29+
litActionPrice: prices[PRODUCT_IDS.LIT_ACTION],
30+
signSessionKeyPrice: prices[PRODUCT_IDS.SIGN_SESSION_KEY],
31+
}))
32+
);
33+
34+
// Call the helper exactly like the SDK does: ask for SIGN_SESSION_KEY prices,
35+
// pass the raw price feed output, and cap the request at two nodes.
36+
const result = getMaxPricesForNodeProduct({
37+
nodePrices,
38+
userMaxPrice: 100n,
39+
productId: PRODUCT_IDS.SIGN_SESSION_KEY,
40+
numRequiredNodes: 2,
41+
});
42+
43+
console.log(
44+
'selected nodes',
45+
result.map(({ url, price }) => ({ url, price }))
46+
);
47+
48+
// After sorting the nodes by the session-key column, the helper should
49+
// return node-b (10) and node-c (20) even though the original array was
50+
// ordered by the decryption price column.
51+
expect(result).toHaveLength(2);
52+
expect(result[0].url).toBe('https://node-b');
53+
expect(result[1].url).toBe('https://node-c');
54+
55+
// Base prices are taken from the SIGN_SESSION_KEY column (10 and 20)
56+
// with the excess (100 - 30 = 70) split evenly.
57+
expect(result[0].price).toBe(10n + 35n);
58+
expect(result[1].price).toBe(20n + 35n);
59+
});
60+
});

packages/networks/src/networks/vNaga/shared/managers/pricing-manager/getMaxPricesForNodeProduct.ts

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,24 @@ export function getMaxPricesForNodeProduct({
2828
productId,
2929
numRequiredNodes,
3030
}: MaxPricesForNodes): { url: string; price: bigint }[] {
31+
// Always evaluate pricing using the product-specific column so we truly pick
32+
// the cheapest validators for that product (the upstream feed is sorted by
33+
// prices[0]/decryption price only).
34+
const sortedNodes = [...nodePrices].sort((a, b) => {
35+
const priceA = a.prices[productId];
36+
const priceB = b.prices[productId];
37+
38+
if (priceA === priceB) {
39+
return 0;
40+
}
41+
42+
return priceA < priceB ? -1 : 1;
43+
});
44+
3145
// If we don't need all nodes to service the request, only use the cheapest `n` of them
3246
const nodesToConsider = numRequiredNodes
33-
? nodePrices.slice(0, numRequiredNodes)
34-
: nodePrices;
47+
? sortedNodes.slice(0, numRequiredNodes)
48+
: sortedNodes;
3549

3650
let totalBaseCost = 0n;
3751

packages/networks/src/networks/vNaga/shared/managers/pricing-manager/schema.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { PRODUCT_IDS } from './constants';
44

55
export const PricingContextSchema = z
66
.object({
7-
product: z.enum(['DECRYPTION', 'SIGN', 'LIT_ACTION']),
7+
product: z.enum(['DECRYPTION', 'SIGN', 'LIT_ACTION', 'SIGN_SESSION_KEY']),
88
userMaxPrice: z.bigint().optional(),
99
nodePrices: z.array(
1010
z.object({ url: z.string(), prices: z.array(z.bigint()) })

0 commit comments

Comments
 (0)