@antseed/node 0.2.152 → 0.2.154
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/buyer-identity-context.d.ts +2 -0
- package/dist/buyer-identity-context.d.ts.map +1 -1
- package/dist/buyer-identity-context.js +1 -0
- package/dist/buyer-identity-context.js.map +1 -1
- package/dist/discovery/announcer.d.ts +2 -0
- package/dist/discovery/announcer.d.ts.map +1 -1
- package/dist/discovery/announcer.js +11 -9
- package/dist/discovery/announcer.js.map +1 -1
- package/dist/health/gas-health-monitor.d.ts +19 -0
- package/dist/health/gas-health-monitor.d.ts.map +1 -1
- package/dist/health/gas-health-monitor.js +21 -0
- package/dist/health/gas-health-monitor.js.map +1 -1
- package/dist/health/model-health-checker.d.ts +52 -0
- package/dist/health/model-health-checker.d.ts.map +1 -1
- package/dist/health/model-health-checker.js +139 -7
- package/dist/health/model-health-checker.js.map +1 -1
- package/dist/health/seller-events.d.ts +24 -0
- package/dist/health/seller-events.d.ts.map +1 -0
- package/dist/health/seller-events.js +71 -0
- package/dist/health/seller-events.js.map +1 -0
- package/dist/health/upstream-credit.d.ts +8 -0
- package/dist/health/upstream-credit.d.ts.map +1 -0
- package/dist/health/upstream-credit.js +22 -0
- package/dist/health/upstream-credit.js.map +1 -0
- package/dist/index.d.ts +13 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -1
- package/dist/index.js.map +1 -1
- package/dist/interfaces/seller-provider.d.ts +4 -1
- package/dist/interfaces/seller-provider.d.ts.map +1 -1
- package/dist/metering/index.d.ts +1 -1
- package/dist/metering/index.d.ts.map +1 -1
- package/dist/metering/index.js.map +1 -1
- package/dist/metering/seller-session-tracker.d.ts +7 -0
- package/dist/metering/seller-session-tracker.d.ts.map +1 -1
- package/dist/metering/seller-session-tracker.js +29 -0
- package/dist/metering/seller-session-tracker.js.map +1 -1
- package/dist/metering/storage.d.ts +146 -6
- package/dist/metering/storage.d.ts.map +1 -1
- package/dist/metering/storage.js +209 -14
- package/dist/metering/storage.js.map +1 -1
- package/dist/node.d.ts +44 -0
- package/dist/node.d.ts.map +1 -1
- package/dist/node.js +122 -11
- package/dist/node.js.map +1 -1
- package/dist/payments/channel-store.d.ts +10 -0
- package/dist/payments/channel-store.d.ts.map +1 -1
- package/dist/payments/channel-store.js +17 -0
- package/dist/payments/channel-store.js.map +1 -1
- package/dist/payments/evm/seller-pools-client.d.ts +9 -0
- package/dist/payments/evm/seller-pools-client.d.ts.map +1 -1
- package/dist/payments/evm/seller-pools-client.js +23 -0
- package/dist/payments/evm/seller-pools-client.js.map +1 -1
- package/dist/payments/free-tier-delegation.d.ts +65 -0
- package/dist/payments/free-tier-delegation.d.ts.map +1 -0
- package/dist/payments/free-tier-delegation.js +145 -0
- package/dist/payments/free-tier-delegation.js.map +1 -0
- package/dist/payments/free-tier-program.d.ts +97 -0
- package/dist/payments/free-tier-program.d.ts.map +1 -0
- package/dist/payments/free-tier-program.js +267 -0
- package/dist/payments/free-tier-program.js.map +1 -0
- package/dist/payments/free-tier-stake-resolver.d.ts +79 -0
- package/dist/payments/free-tier-stake-resolver.d.ts.map +1 -0
- package/dist/payments/free-tier-stake-resolver.js +152 -0
- package/dist/payments/free-tier-stake-resolver.js.map +1 -0
- package/dist/payments/free-tier-stake.d.ts +101 -0
- package/dist/payments/free-tier-stake.d.ts.map +1 -0
- package/dist/payments/free-tier-stake.js +116 -0
- package/dist/payments/free-tier-stake.js.map +1 -0
- package/dist/payments/index.d.ts +7 -1
- package/dist/payments/index.d.ts.map +1 -1
- package/dist/payments/index.js +3 -0
- package/dist/payments/index.js.map +1 -1
- package/dist/payments/seller-free-tier-limiter.d.ts +124 -6
- package/dist/payments/seller-free-tier-limiter.d.ts.map +1 -1
- package/dist/payments/seller-free-tier-limiter.js +342 -32
- package/dist/payments/seller-free-tier-limiter.js.map +1 -1
- package/dist/payments/seller-free-usage-manager.d.ts.map +1 -1
- package/dist/payments/seller-free-usage-manager.js +5 -1
- package/dist/payments/seller-free-usage-manager.js.map +1 -1
- package/dist/seller-request-handler.d.ts.map +1 -1
- package/dist/seller-request-handler.js +113 -19
- package/dist/seller-request-handler.js.map +1 -1
- package/dist/storage/migrate.d.ts +6 -0
- package/dist/storage/migrate.d.ts.map +1 -1
- package/dist/storage/migrate.js +11 -0
- package/dist/storage/migrate.js.map +1 -1
- package/dist/storage/migrations/metering/004_add_free_tier_staked_usage.d.ts +3 -0
- package/dist/storage/migrations/metering/004_add_free_tier_staked_usage.d.ts.map +1 -0
- package/dist/storage/migrations/metering/004_add_free_tier_staked_usage.js +21 -0
- package/dist/storage/migrations/metering/004_add_free_tier_staked_usage.js.map +1 -0
- package/dist/storage/migrations/metering/005_add_free_tier_scope.d.ts +8 -0
- package/dist/storage/migrations/metering/005_add_free_tier_scope.d.ts.map +1 -0
- package/dist/storage/migrations/metering/005_add_free_tier_scope.js +23 -0
- package/dist/storage/migrations/metering/005_add_free_tier_scope.js.map +1 -0
- package/dist/storage/migrations/metering/006_add_event_service.d.ts +4 -0
- package/dist/storage/migrations/metering/006_add_event_service.d.ts.map +1 -0
- package/dist/storage/migrations/metering/006_add_event_service.js +11 -0
- package/dist/storage/migrations/metering/006_add_event_service.js.map +1 -0
- package/dist/storage/migrations/metering/007_add_event_detail.d.ts +4 -0
- package/dist/storage/migrations/metering/007_add_event_detail.d.ts.map +1 -0
- package/dist/storage/migrations/metering/007_add_event_detail.js +12 -0
- package/dist/storage/migrations/metering/007_add_event_detail.js.map +1 -0
- package/dist/storage/migrations/metering/008_add_event_request_id.d.ts +4 -0
- package/dist/storage/migrations/metering/008_add_event_request_id.d.ts.map +1 -0
- package/dist/storage/migrations/metering/008_add_event_request_id.js +10 -0
- package/dist/storage/migrations/metering/008_add_event_request_id.js.map +1 -0
- package/dist/storage/migrations/metering/009_index_receipts_by_event.d.ts +4 -0
- package/dist/storage/migrations/metering/009_index_receipts_by_event.d.ts.map +1 -0
- package/dist/storage/migrations/metering/009_index_receipts_by_event.js +9 -0
- package/dist/storage/migrations/metering/009_index_receipts_by_event.js.map +1 -0
- package/dist/storage/migrations/metering/010_repair_free_tier_usage.d.ts +8 -0
- package/dist/storage/migrations/metering/010_repair_free_tier_usage.d.ts.map +1 -0
- package/dist/storage/migrations/metering/010_repair_free_tier_usage.js +35 -0
- package/dist/storage/migrations/metering/010_repair_free_tier_usage.js.map +1 -0
- package/dist/storage/migrations/metering/index.d.ts.map +1 -1
- package/dist/storage/migrations/metering/index.js +8 -1
- package/dist/storage/migrations/metering/index.js.map +1 -1
- package/dist/types/metering.d.ts +8 -0
- package/dist/types/metering.d.ts.map +1 -1
- package/dist/utils/file-lock.d.ts +12 -0
- package/dist/utils/file-lock.d.ts.map +1 -0
- package/dist/utils/file-lock.js +58 -0
- package/dist/utils/file-lock.js.map +1 -0
- package/package.json +11 -3
package/dist/node.js
CHANGED
|
@@ -6,6 +6,7 @@ import { computeTrustScore } from './reputation/trust-score.js';
|
|
|
6
6
|
import { TrustSignalsClient } from './payments/evm/trust-signals-client.js';
|
|
7
7
|
import { loadOrCreateIdentity } from "./p2p/identity.js";
|
|
8
8
|
import { peerIdToAddress } from "./types/peer.js";
|
|
9
|
+
import { isFreeUnitBillingModel } from "./billing/unit.js";
|
|
9
10
|
import { MeteringStorage } from "./metering/storage.js";
|
|
10
11
|
import { ResourceOwnershipStore } from "./resources/resource-ownership-store.js";
|
|
11
12
|
import { ReceiptGenerator } from "./metering/receipt-generator.js";
|
|
@@ -14,7 +15,7 @@ import { ConnectionState } from "./types/connection.js";
|
|
|
14
15
|
import { DHTNode, DEFAULT_DHT_CONFIG, SUBNET_COUNT, } from "./discovery/dht-node.js";
|
|
15
16
|
import { toBootstrapConfig, OFFICIAL_BOOTSTRAP_NODES, mergeBootstrapNodes } from "./discovery/bootstrap.js";
|
|
16
17
|
import { ConnectionManager, } from "./p2p/connection-manager.js";
|
|
17
|
-
import { PeerAnnouncer, } from "./discovery/announcer.js";
|
|
18
|
+
import { PeerAnnouncer, builtinPeerCapabilities, } from "./discovery/announcer.js";
|
|
18
19
|
import { verifyPeerMetadataDomains } from "./discovery/domain-verification.js";
|
|
19
20
|
import { verifyPeerMetadataGithub } from "./discovery/github-verification.js";
|
|
20
21
|
import { PeerLookup, DEFAULT_LOOKUP_CONFIG, } from "./discovery/peer-lookup.js";
|
|
@@ -36,11 +37,15 @@ import { signUtf8 } from "./p2p/identity.js";
|
|
|
36
37
|
import { BalanceManager, DepositsClient, ChannelsClient, FreeUsageClient, BuyerFreeUsageManager, SellerFreeUsageManager, SellerFreeTierLimiter, StakingClient, ChannelStore, CHANNEL_KIND, CHANNEL_ROLE, CHANNEL_STATUS, } from "./payments/index.js";
|
|
37
38
|
import { debugLog, debugWarn } from "./utils/debug.js";
|
|
38
39
|
import { parsePublicAddress } from "./discovery/public-address.js";
|
|
40
|
+
import { MAX_PEER_CAPABILITIES } from "./discovery/metadata-validator.js";
|
|
39
41
|
import { sanitizePeerDisplayName } from "./discovery/display-name.js";
|
|
40
42
|
import { BuyerPaymentManager } from "./payments/buyer-payment-manager.js";
|
|
41
43
|
import { BuyerPaymentNegotiator } from "./payments/buyer-payment-negotiator.js";
|
|
42
44
|
import { RpcHealthMonitor } from "./payments/rpc-health.js";
|
|
43
45
|
import { SellerAddressResolver } from "./discovery/seller-address-resolver.js";
|
|
46
|
+
import { SellerPoolsClient } from "./payments/evm/seller-pools-client.js";
|
|
47
|
+
import { FreeTierStakeResolver } from "./payments/free-tier-stake-resolver.js";
|
|
48
|
+
import { encodeFreeTierDelegationsHeader } from "./payments/free-tier-delegation.js";
|
|
44
49
|
import { Contract as EthersContract } from "ethers";
|
|
45
50
|
import { SellerPaymentManager } from "./payments/seller-payment-manager.js";
|
|
46
51
|
import { IdentityClient } from "./payments/evm/identity-client.js";
|
|
@@ -154,6 +159,8 @@ export class AntseedNode extends EventEmitter {
|
|
|
154
159
|
_buyerIdentities = new Map();
|
|
155
160
|
/** Seller-side deposit-sweep relayer (initialized when configured + enabled). */
|
|
156
161
|
_depositRelayer = null;
|
|
162
|
+
/** Settles or closes a buyer's channel when its metering session goes idle; removed on stop. */
|
|
163
|
+
_settleOnIdle = null;
|
|
157
164
|
/** Seller-side request handler (provider matching, execution, load tracking). */
|
|
158
165
|
_sellerHandler = null;
|
|
159
166
|
/** Buyer-side payment manager (initialized when buyer has payment config). */
|
|
@@ -328,7 +335,7 @@ export class AntseedNode extends EventEmitter {
|
|
|
328
335
|
}
|
|
329
336
|
const dataDir = this._config.dataDir ?? join(homedir(), ".antseed");
|
|
330
337
|
// Load or create identity
|
|
331
|
-
this._identity = await loadOrCreateIdentity(this._config.identityStore ?? dataDir);
|
|
338
|
+
this._identity = this._config.identity ?? await loadOrCreateIdentity(this._config.identityStore ?? dataDir);
|
|
332
339
|
debugLog(`[Node] Identity loaded: ${this._identity.peerId.slice(0, 12)}...`);
|
|
333
340
|
// Determine bootstrap nodes — merge official + any user-configured nodes unless
|
|
334
341
|
// noOfficialBootstrap is set (e.g. isolated local testing).
|
|
@@ -336,11 +343,22 @@ export class AntseedNode extends EventEmitter {
|
|
|
336
343
|
? (this._config.bootstrapNodes ?? [])
|
|
337
344
|
: mergeBootstrapNodes(OFFICIAL_BOOTSTRAP_NODES, this._config.bootstrapNodes ?? []));
|
|
338
345
|
debugLog(`[Node] Starting as ${this._config.role} with ${bootstrapNodes.length} bootstrap node(s)`);
|
|
339
|
-
|
|
340
|
-
|
|
346
|
+
try {
|
|
347
|
+
if (this._config.role === "seller") {
|
|
348
|
+
await this._startSeller(bootstrapNodes);
|
|
349
|
+
}
|
|
350
|
+
else {
|
|
351
|
+
await this._startBuyer(bootstrapNodes);
|
|
352
|
+
}
|
|
341
353
|
}
|
|
342
|
-
|
|
343
|
-
|
|
354
|
+
catch (error) {
|
|
355
|
+
// A start that fails partway (say the DHT after the payment store and
|
|
356
|
+
// RPC monitor) releases what it opened, so a retry starts clean.
|
|
357
|
+
this._started = true;
|
|
358
|
+
await this.stop().catch((err) => {
|
|
359
|
+
debugWarn(`[Node] Cleanup after a failed start failed: ${err instanceof Error ? err.message : err}`);
|
|
360
|
+
});
|
|
361
|
+
throw error;
|
|
344
362
|
}
|
|
345
363
|
this._started = true;
|
|
346
364
|
debugLog(`[Node] Started successfully`);
|
|
@@ -485,6 +503,12 @@ export class AntseedNode extends EventEmitter {
|
|
|
485
503
|
this._buyerHandler = null;
|
|
486
504
|
this._backgroundPeerDiscoveryPromise = null;
|
|
487
505
|
this._sellerPaymentManager = null;
|
|
506
|
+
if (this._settleOnIdle) {
|
|
507
|
+
this.off("session:finalized", this._settleOnIdle);
|
|
508
|
+
this._settleOnIdle = null;
|
|
509
|
+
}
|
|
510
|
+
this._depositRelayer = null;
|
|
511
|
+
this._advertisingPausedReason = null;
|
|
488
512
|
this._sessionTracker = null;
|
|
489
513
|
this._started = false;
|
|
490
514
|
this.emit("stopped");
|
|
@@ -1231,6 +1255,7 @@ export class AntseedNode extends EventEmitter {
|
|
|
1231
1255
|
},
|
|
1232
1256
|
maxUploadBodyBytes: this._config.maxUploadBodyBytes,
|
|
1233
1257
|
requireSecureTransport: this._config.requireSecureTransport,
|
|
1258
|
+
freeTierDelegationsHeader: () => this._freeTierDelegationsHeader(identity.wallet.address),
|
|
1234
1259
|
shared: {
|
|
1235
1260
|
channelStore: this._channelStore,
|
|
1236
1261
|
depositsClient: this._depositsClient,
|
|
@@ -1454,12 +1479,16 @@ export class AntseedNode extends EventEmitter {
|
|
|
1454
1479
|
this._sellerFreeTierLimiter = this._config.freeTier
|
|
1455
1480
|
? new SellerFreeTierLimiter(this._config.freeTier, this._metering)
|
|
1456
1481
|
: null;
|
|
1482
|
+
const offered = this._offeredServicesByPrice();
|
|
1483
|
+
this._sellerFreeTierLimiter?.setPaidServices(offered.paid);
|
|
1484
|
+
this._sellerFreeTierLimiter?.setFreeServices(offered.free);
|
|
1457
1485
|
await this._initializePayments(dataDir);
|
|
1458
1486
|
this._warnIfFreeUsageMeteringUnavailable();
|
|
1487
|
+
this._initializeFreeTierStakeResolver(identity);
|
|
1459
1488
|
// Wire idle session events to on-chain settlement
|
|
1460
1489
|
if (this._sellerPaymentManager) {
|
|
1461
1490
|
const spm = this._sellerPaymentManager;
|
|
1462
|
-
this.
|
|
1491
|
+
this._settleOnIdle = (info) => {
|
|
1463
1492
|
if (info.reason === "idle-settle") {
|
|
1464
1493
|
debugLog(`[Node] Idle settle for buyer ${info.buyerPeerId.slice(0, 12)}... — settling channel (keeping open)`);
|
|
1465
1494
|
void spm.settleSession(info.buyerPeerId, { settleOnly: true });
|
|
@@ -1468,7 +1497,8 @@ export class AntseedNode extends EventEmitter {
|
|
|
1468
1497
|
debugLog(`[Node] Idle timeout for buyer ${info.buyerPeerId.slice(0, 12)}... — closing channel`);
|
|
1469
1498
|
void spm.settleSession(info.buyerPeerId, { cleanupOnFailure: true });
|
|
1470
1499
|
}
|
|
1471
|
-
}
|
|
1500
|
+
};
|
|
1501
|
+
this.on("session:finalized", this._settleOnIdle);
|
|
1472
1502
|
}
|
|
1473
1503
|
// Start DHT
|
|
1474
1504
|
this._dht = new DHTNode(this._createDHTConfig(dhtPort, bootstrapNodes));
|
|
@@ -1506,10 +1536,12 @@ export class AntseedNode extends EventEmitter {
|
|
|
1506
1536
|
}
|
|
1507
1537
|
// Set up announcer for providers
|
|
1508
1538
|
if (this._providers.length > 0) {
|
|
1509
|
-
const
|
|
1539
|
+
const baseCapabilities = [
|
|
1510
1540
|
...(this._connectionManager.supportsWebRtc ? [CONNECTION_CAPABILITY_WEBRTC_V1] : []),
|
|
1511
1541
|
...(this._config.capabilities ?? []),
|
|
1512
1542
|
];
|
|
1543
|
+
const usedCapabilities = builtinPeerCapabilities(this._depositRelayer !== null).length + baseCapabilities.length;
|
|
1544
|
+
const extraCapabilities = [...baseCapabilities, ...this._freeTierCapabilities(usedCapabilities)];
|
|
1513
1545
|
const announcerConfig = {
|
|
1514
1546
|
identity,
|
|
1515
1547
|
dht: this._dht,
|
|
@@ -1666,6 +1698,7 @@ export class AntseedNode extends EventEmitter {
|
|
|
1666
1698
|
getMux: (peerId, conn) => this._getOrCreateMux(peerId, conn),
|
|
1667
1699
|
getVerificationMux: (peerId, conn) => this._getOrCreateVerificationMux(peerId, conn),
|
|
1668
1700
|
registerPaymentMux: (peerId, pmux) => this._paymentMuxes.set(peerId, pmux),
|
|
1701
|
+
freeTierDelegationsHeader: () => this._freeTierDelegationsHeader(identity.wallet.address),
|
|
1669
1702
|
});
|
|
1670
1703
|
debugLog(`[Node] Buyer ready — DHT running on port ${this._dht.getPort()}`);
|
|
1671
1704
|
}
|
|
@@ -1841,7 +1874,7 @@ export class AntseedNode extends EventEmitter {
|
|
|
1841
1874
|
sellerContracts.set(sellerContract, contract);
|
|
1842
1875
|
}
|
|
1843
1876
|
else {
|
|
1844
|
-
contract = new EthersContract(sellerContract, isOperatorAbi, channelsClientRef.provider);
|
|
1877
|
+
contract = new EthersContract(sellerContract, isOperatorAbi, payments.readProvider ?? channelsClientRef.provider);
|
|
1845
1878
|
if (sellerContracts.size >= SELLER_CONTRACTS_MAX) {
|
|
1846
1879
|
const oldest = sellerContracts.keys().next().value;
|
|
1847
1880
|
if (oldest !== undefined)
|
|
@@ -1894,7 +1927,7 @@ export class AntseedNode extends EventEmitter {
|
|
|
1894
1927
|
debugLog(`[Node] StakingClient initialized (contract=${payments.stakingAddress.slice(0, 10)}...)`);
|
|
1895
1928
|
}
|
|
1896
1929
|
if (this._channelsClient && payments.stakingAddress && payments.channelsAddress) {
|
|
1897
|
-
this._trustSignalsClient = new TrustSignalsClient(this._channelsClient.provider, {
|
|
1930
|
+
this._trustSignalsClient = new TrustSignalsClient(payments.readProvider ?? this._channelsClient.provider, {
|
|
1898
1931
|
sellerRegistry: payments.stakingAddress,
|
|
1899
1932
|
channels: payments.channelsAddress,
|
|
1900
1933
|
...(payments.sellerPoolsAddress ? { sellerPools: payments.sellerPoolsAddress } : {}),
|
|
@@ -2294,6 +2327,84 @@ export class AntseedNode extends EventEmitter {
|
|
|
2294
2327
|
onChainGhostCount: result.metadata.onChainGhostCount,
|
|
2295
2328
|
};
|
|
2296
2329
|
}
|
|
2330
|
+
/** Replace the buyer's free-tier delegations; later requests send the new set. */
|
|
2331
|
+
setFreeTierDelegations(delegations) {
|
|
2332
|
+
this._config.freeTierDelegations = [...delegations];
|
|
2333
|
+
}
|
|
2334
|
+
/** Header value carrying the unexpired delegations to `buyerAddress`, or null when there are none. */
|
|
2335
|
+
_freeTierDelegationsHeader(buyerAddress) {
|
|
2336
|
+
const nowSeconds = Date.now() / 1000;
|
|
2337
|
+
const delegations = (this._config.freeTierDelegations ?? []).filter((delegation) => delegation.buyer.toLowerCase() === buyerAddress.toLowerCase() && delegation.expiresAt > nowSeconds);
|
|
2338
|
+
return delegations.length > 0 ? encodeFreeTierDelegationsHeader(delegations) : null;
|
|
2339
|
+
}
|
|
2340
|
+
/**
|
|
2341
|
+
* Back staked free-tier tiers with on-chain reads: the positions of the
|
|
2342
|
+
* buyer and of every staker that signed a delegation to it in this seller's
|
|
2343
|
+
* pool. Without the seller pools contract every buyer keeps the base limits
|
|
2344
|
+
* and no tiers are advertised.
|
|
2345
|
+
*/
|
|
2346
|
+
/**
|
|
2347
|
+
* Free-tier programs to advertise within what is left of the peer
|
|
2348
|
+
* capability limit. Programs that do not fit are still enforced; buyers
|
|
2349
|
+
* learn them from the seller's refusals instead.
|
|
2350
|
+
*/
|
|
2351
|
+
/**
|
|
2352
|
+
* Offered services by whether some provider charges for them (tokens or any
|
|
2353
|
+
* priced unit-billing model), as the request handler decides it. A paid
|
|
2354
|
+
* service's allowance never admits a free-usage channel; the free ones decide admission.
|
|
2355
|
+
*/
|
|
2356
|
+
_offeredServicesByPrice() {
|
|
2357
|
+
const paid = new Set();
|
|
2358
|
+
const offered = new Set();
|
|
2359
|
+
for (const provider of this._providers) {
|
|
2360
|
+
for (const service of provider.services) {
|
|
2361
|
+
offered.add(service);
|
|
2362
|
+
const pricing = provider.pricing.services?.[service] ?? provider.pricing.defaults;
|
|
2363
|
+
const tokenPriced = pricing.inputUsdPerMillion > 0 || pricing.outputUsdPerMillion > 0 || (pricing.cachedInputUsdPerMillion ?? 0) > 0;
|
|
2364
|
+
const unitPriced = Object.values(provider.serviceUnitBillingModels?.[service] ?? {})
|
|
2365
|
+
.some((model) => model !== undefined && !isFreeUnitBillingModel(model));
|
|
2366
|
+
if (tokenPriced || unitPriced)
|
|
2367
|
+
paid.add(service);
|
|
2368
|
+
}
|
|
2369
|
+
}
|
|
2370
|
+
return { paid: [...paid], free: [...offered].filter((service) => !paid.has(service)) };
|
|
2371
|
+
}
|
|
2372
|
+
_freeTierCapabilities(usedCapabilities) {
|
|
2373
|
+
const limiter = this._sellerFreeTierLimiter;
|
|
2374
|
+
if (!limiter)
|
|
2375
|
+
return [];
|
|
2376
|
+
const capabilities = limiter.capabilities(MAX_PEER_CAPABILITIES - usedCapabilities);
|
|
2377
|
+
if (capabilities.length < limiter.capabilities().length) {
|
|
2378
|
+
debugWarn(`[Node] Not every free-tier program fits in peer metadata (${MAX_PEER_CAPABILITIES} capabilities max); ` +
|
|
2379
|
+
`the rest are enforced but not advertised`);
|
|
2380
|
+
}
|
|
2381
|
+
return capabilities;
|
|
2382
|
+
}
|
|
2383
|
+
_initializeFreeTierStakeResolver(identity) {
|
|
2384
|
+
const limiter = this._sellerFreeTierLimiter;
|
|
2385
|
+
const payments = this._config.payments;
|
|
2386
|
+
if (!limiter || !limiter.hasStakeTiers)
|
|
2387
|
+
return;
|
|
2388
|
+
if (!payments?.rpcUrl || !payments.sellerPoolsAddress) {
|
|
2389
|
+
debugLog("[Node] Staked free-tier tiers disabled: seller pools contract not configured");
|
|
2390
|
+
return;
|
|
2391
|
+
}
|
|
2392
|
+
const sellerPools = new SellerPoolsClient({
|
|
2393
|
+
rpcUrl: payments.rpcUrl,
|
|
2394
|
+
...(payments.fallbackRpcUrls ? { fallbackRpcUrls: payments.fallbackRpcUrls } : {}),
|
|
2395
|
+
contractAddress: payments.sellerPoolsAddress,
|
|
2396
|
+
// Only stake writes use the token; the free tier only reads.
|
|
2397
|
+
antsTokenAddress: "0x0000000000000000000000000000000000000000",
|
|
2398
|
+
...(payments.chainId ? { evmChainId: payments.chainId } : {}),
|
|
2399
|
+
});
|
|
2400
|
+
const sellerAddress = this._config.sellerContract?.sellerContract ?? identity.wallet.address;
|
|
2401
|
+
limiter.setStakeResolver(new FreeTierStakeResolver({
|
|
2402
|
+
sellerAgentId: () => sellerPools.agentIdForSeller(sellerAddress),
|
|
2403
|
+
currentEpoch: () => sellerPools.currentEpoch(),
|
|
2404
|
+
stakerPositions: (staker, agentId, epoch) => sellerPools.stakerPositionsInPool(staker, agentId, epoch),
|
|
2405
|
+
}), payments.chainId ?? 8453);
|
|
2406
|
+
debugLog(`[Node] Staked free-tier tiers enabled (pools=${payments.sellerPoolsAddress.slice(0, 10)}...)`);
|
|
2407
|
+
}
|
|
2297
2408
|
_warnIfFreeUsageMeteringUnavailable() {
|
|
2298
2409
|
if (this._sellerFreeUsageManager || !this._hasFreePricedService())
|
|
2299
2410
|
return;
|