@layr-labs/ecloud-sdk 1.0.0-dev.2 → 1.0.0-dev.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.
@@ -1,5 +1,5 @@
1
1
  import { Address, Hex, WalletClient, PublicClient } from 'viem';
2
- import { a3 as SubscriptionOpts, a1 as SubscribeResponse, Z as ProductSubscriptionResponse, g as CancelResponse } from './index-U2vKBrry.cjs';
2
+ import { a6 as SubscriptionOpts, a4 as SubscribeResponse, a0 as ProductSubscriptionResponse, g as CancelResponse, M as PaymentMethodsResponse, m as CreditPurchaseResponse } from './index-BoCE0hIh.cjs';
3
3
 
4
4
  /**
5
5
  * Main Billing namespace entry point
@@ -8,11 +8,14 @@ import { a3 as SubscriptionOpts, a1 as SubscribeResponse, Z as ProductSubscripti
8
8
  * (privateKeyToAccount) and external signers (MetaMask, etc.).
9
9
  */
10
10
 
11
+ type BillingChain = "ethereum" | "base";
11
12
  interface TopUpOpts {
12
13
  /** Amount in raw USDC units (6 decimals, e.g. 50_000_000n = 50 USDC) */
13
14
  amount: bigint;
14
15
  /** Target account for purchaseCreditsFor (defaults to wallet address) */
15
16
  account?: Address;
17
+ /** Which blockchain to transact on (defaults to "ethereum") */
18
+ chain?: BillingChain;
16
19
  }
17
20
  interface TopUpResult {
18
21
  txHash: Hex;
@@ -30,9 +33,15 @@ interface BillingModule {
30
33
  getStatus: (opts?: SubscriptionOpts) => Promise<ProductSubscriptionResponse>;
31
34
  cancel: (opts?: SubscriptionOpts) => Promise<CancelResponse>;
32
35
  /** Read on-chain state needed for top-up */
33
- getTopUpInfo: () => Promise<TopUpInfo>;
36
+ getTopUpInfo: (opts?: {
37
+ chain?: BillingChain;
38
+ }) => Promise<TopUpInfo>;
34
39
  /** Purchase credits with USDC on-chain */
35
40
  topUp: (opts: TopUpOpts) => Promise<TopUpResult>;
41
+ getPaymentMethods: () => Promise<PaymentMethodsResponse>;
42
+ purchaseCredits: (amountCents: number, paymentMethodId?: string) => Promise<CreditPurchaseResponse>;
43
+ /** Check if Base chain is configured for this environment */
44
+ hasBaseSupport: () => boolean;
36
45
  }
37
46
  interface BillingModuleConfig {
38
47
  verbose?: boolean;
@@ -40,7 +49,8 @@ interface BillingModuleConfig {
40
49
  skipTelemetry?: boolean;
41
50
  publicClient: PublicClient;
42
51
  environment: string;
52
+ privateKey?: Hex;
43
53
  }
44
54
  declare function createBillingModule(config: BillingModuleConfig): BillingModule;
45
55
 
46
- export { type BillingModule, type BillingModuleConfig, type TopUpInfo, type TopUpOpts, type TopUpResult, createBillingModule };
56
+ export { type BillingChain, type BillingModule, type BillingModuleConfig, type TopUpInfo, type TopUpOpts, type TopUpResult, createBillingModule };
package/dist/billing.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { Address, Hex, WalletClient, PublicClient } from 'viem';
2
- import { a3 as SubscriptionOpts, a1 as SubscribeResponse, Z as ProductSubscriptionResponse, g as CancelResponse } from './index-U2vKBrry.js';
2
+ import { a6 as SubscriptionOpts, a4 as SubscribeResponse, a0 as ProductSubscriptionResponse, g as CancelResponse, M as PaymentMethodsResponse, m as CreditPurchaseResponse } from './index-BoCE0hIh.js';
3
3
 
4
4
  /**
5
5
  * Main Billing namespace entry point
@@ -8,11 +8,14 @@ import { a3 as SubscriptionOpts, a1 as SubscribeResponse, Z as ProductSubscripti
8
8
  * (privateKeyToAccount) and external signers (MetaMask, etc.).
9
9
  */
10
10
 
11
+ type BillingChain = "ethereum" | "base";
11
12
  interface TopUpOpts {
12
13
  /** Amount in raw USDC units (6 decimals, e.g. 50_000_000n = 50 USDC) */
13
14
  amount: bigint;
14
15
  /** Target account for purchaseCreditsFor (defaults to wallet address) */
15
16
  account?: Address;
17
+ /** Which blockchain to transact on (defaults to "ethereum") */
18
+ chain?: BillingChain;
16
19
  }
17
20
  interface TopUpResult {
18
21
  txHash: Hex;
@@ -30,9 +33,15 @@ interface BillingModule {
30
33
  getStatus: (opts?: SubscriptionOpts) => Promise<ProductSubscriptionResponse>;
31
34
  cancel: (opts?: SubscriptionOpts) => Promise<CancelResponse>;
32
35
  /** Read on-chain state needed for top-up */
33
- getTopUpInfo: () => Promise<TopUpInfo>;
36
+ getTopUpInfo: (opts?: {
37
+ chain?: BillingChain;
38
+ }) => Promise<TopUpInfo>;
34
39
  /** Purchase credits with USDC on-chain */
35
40
  topUp: (opts: TopUpOpts) => Promise<TopUpResult>;
41
+ getPaymentMethods: () => Promise<PaymentMethodsResponse>;
42
+ purchaseCredits: (amountCents: number, paymentMethodId?: string) => Promise<CreditPurchaseResponse>;
43
+ /** Check if Base chain is configured for this environment */
44
+ hasBaseSupport: () => boolean;
36
45
  }
37
46
  interface BillingModuleConfig {
38
47
  verbose?: boolean;
@@ -40,7 +49,8 @@ interface BillingModuleConfig {
40
49
  skipTelemetry?: boolean;
41
50
  publicClient: PublicClient;
42
51
  environment: string;
52
+ privateKey?: Hex;
43
53
  }
44
54
  declare function createBillingModule(config: BillingModuleConfig): BillingModule;
45
55
 
46
- export { type BillingModule, type BillingModuleConfig, type TopUpInfo, type TopUpOpts, type TopUpResult, createBillingModule };
56
+ export { type BillingChain, type BillingModule, type BillingModuleConfig, type TopUpInfo, type TopUpOpts, type TopUpResult, createBillingModule };
package/dist/billing.js CHANGED
@@ -283,6 +283,20 @@ var BillingApiClient = class {
283
283
  const endpoint = `${this.config.billingApiServerURL}/products/${productId}/subscription`;
284
284
  await this.makeAuthenticatedRequest(endpoint, "DELETE", productId);
285
285
  }
286
+ async getPaymentMethods() {
287
+ const endpoint = `${this.config.billingApiServerURL}/v1/payment-methods`;
288
+ const resp = await this.makeAuthenticatedRequest(endpoint, "GET", "compute");
289
+ return resp.json();
290
+ }
291
+ async purchaseCredits(amountCents, paymentMethodId) {
292
+ const endpoint = `${this.config.billingApiServerURL}/v1/credits/purchase`;
293
+ const body = { amountCents };
294
+ if (paymentMethodId) {
295
+ body.paymentMethodId = paymentMethodId;
296
+ }
297
+ const resp = await this.makeAuthenticatedRequest(endpoint, "POST", "compute", body);
298
+ return resp.json();
299
+ }
286
300
  // ==========================================================================
287
301
  // Internal Methods
288
302
  // ==========================================================================
@@ -292,10 +306,22 @@ var BillingApiClient = class {
292
306
  * Uses session auth if useSession is true, otherwise uses EIP-712 signature auth.
293
307
  */
294
308
  async makeAuthenticatedRequest(url, method, productId, body) {
295
- if (this.useSession) {
296
- return this.makeSessionAuthenticatedRequest(url, method, body);
309
+ if (this.options.verbose) {
310
+ console.debug(`[BillingAPI] ${method} ${url}`);
311
+ if (body) {
312
+ console.debug(`[BillingAPI] Payload:`, JSON.stringify(body, null, 2));
313
+ }
314
+ }
315
+ const resp = this.useSession ? await this.makeSessionAuthenticatedRequest(url, method, body) : await this.makeSignatureAuthenticatedRequest(url, method, productId, body);
316
+ if (this.options.verbose) {
317
+ const data = await resp.json();
318
+ console.debug(`[BillingAPI] Response:`, JSON.stringify(data, null, 2));
319
+ return {
320
+ json: async () => data,
321
+ text: async () => JSON.stringify(data)
322
+ };
297
323
  }
298
- return this.makeSignatureAuthenticatedRequest(url, method, productId, body);
324
+ return resp;
299
325
  }
300
326
  /**
301
327
  * Make a request using session-based authentication (cookies)
@@ -403,6 +429,7 @@ Please check:
403
429
  // src/client/common/config/environment.ts
404
430
  var SEPOLIA_CHAIN_ID = 11155111;
405
431
  var MAINNET_CHAIN_ID = 1;
432
+ var BASE_SEPOLIA_CHAIN_ID = 84532;
406
433
  var CommonAddresses = {
407
434
  ERC7702Delegator: "0x63c0c19a282a1b52b07dd5a65b58948a07dae32b"
408
435
  };
@@ -432,7 +459,9 @@ var ENVIRONMENTS = {
432
459
  kmsServerURL: "http://10.128.0.57:8080",
433
460
  userApiServerURL: "https://userapi-compute-sepolia-dev.eigencloud.xyz",
434
461
  defaultRPCURL: "https://ethereum-sepolia-rpc.publicnode.com",
435
- usdcCreditsAddress: "0xbdA3897c3A428763B59015C64AB766c288C97376"
462
+ usdcCreditsAddress: "0xbdA3897c3A428763B59015C64AB766c288C97376",
463
+ baseUsdcCreditsAddress: "0x7673a47463F80c6a3553Db9E54c8cDcd5313d0ac",
464
+ baseRPCURL: "https://base-sepolia-rpc.publicnode.com"
436
465
  },
437
466
  sepolia: {
438
467
  name: "sepolia",
@@ -444,7 +473,9 @@ var ENVIRONMENTS = {
444
473
  userApiServerURL: "https://userapi-compute-sepolia-prod.eigencloud.xyz",
445
474
  defaultRPCURL: "https://ethereum-sepolia-rpc.publicnode.com",
446
475
  billingRPCURL: "https://ethereum-rpc.publicnode.com",
447
- usdcCreditsAddress: "0xed9c88640ca9149Bd9f7ee6620074af10F2E145d"
476
+ usdcCreditsAddress: "0xed9c88640ca9149Bd9f7ee6620074af10F2E145d",
477
+ baseUsdcCreditsAddress: "0x7673a47463F80c6a3553Db9E54c8cDcd5313d0ac",
478
+ baseRPCURL: "https://base-sepolia-rpc.publicnode.com"
448
479
  },
449
480
  "mainnet-alpha": {
450
481
  name: "mainnet-alpha",
@@ -489,7 +520,13 @@ function getEnvironmentConfig(environment, chainID) {
489
520
  return {
490
521
  ...env,
491
522
  chainID: BigInt(resolvedChainID),
492
- ...apiUrlOverride ? { userApiServerURL: apiUrlOverride } : {}
523
+ ...apiUrlOverride ? { userApiServerURL: apiUrlOverride } : {},
524
+ ...process.env.ECLOUD_USER_API_URL && {
525
+ userApiServerURL: process.env.ECLOUD_USER_API_URL
526
+ },
527
+ ...process.env.ECLOUD_RPC_URL && {
528
+ defaultRPCURL: process.env.ECLOUD_RPC_URL
529
+ }
493
530
  };
494
531
  }
495
532
  function getBillingEnvironmentConfig(build) {
@@ -501,7 +538,12 @@ function getBillingEnvironmentConfig(build) {
501
538
  if (apiUrlOverride) {
502
539
  return { billingApiServerURL: apiUrlOverride };
503
540
  }
504
- return config;
541
+ return {
542
+ ...config,
543
+ ...process.env.ECLOUD_BILLING_API_URL && {
544
+ billingApiServerURL: process.env.ECLOUD_BILLING_API_URL
545
+ }
546
+ };
505
547
  }
506
548
  function getBuildType() {
507
549
  const buildTimeType = true ? "dev"?.toLowerCase() : void 0;
@@ -523,6 +565,41 @@ function isEnvironmentAvailable(environment) {
523
565
  return getAvailableEnvironments().includes(environment);
524
566
  }
525
567
 
568
+ // src/client/common/utils/helpers.ts
569
+ import { extractChain, createPublicClient, createWalletClient, http, fallback } from "viem";
570
+ import { sepolia as sepolia2 } from "viem/chains";
571
+ import { privateKeyToAccount } from "viem/accounts";
572
+
573
+ // src/client/common/constants.ts
574
+ import { sepolia, mainnet, baseSepolia } from "viem/chains";
575
+ var SUPPORTED_CHAINS = [mainnet, sepolia, baseSepolia];
576
+
577
+ // src/client/common/utils/helpers.ts
578
+ function getChainFromID(chainID, fallback2 = sepolia2) {
579
+ const id = Number(chainID);
580
+ return extractChain({ chains: SUPPORTED_CHAINS, id }) || fallback2;
581
+ }
582
+ function createClients(options) {
583
+ const { privateKey, rpcUrl, chainId } = options;
584
+ const privateKeyHex = addHexPrefix(privateKey);
585
+ const account = privateKeyToAccount(privateKeyHex);
586
+ const chain = getChainFromID(chainId);
587
+ const transport = typeof rpcUrl === "string" ? http(rpcUrl) : fallback(rpcUrl.map((url) => http(url)));
588
+ const publicClient = createPublicClient({
589
+ chain,
590
+ transport
591
+ });
592
+ const walletClient = createWalletClient({
593
+ account,
594
+ chain,
595
+ transport
596
+ });
597
+ return { walletClient, publicClient };
598
+ }
599
+ function addHexPrefix(value) {
600
+ return value.startsWith("0x") ? value : `0x${value}`;
601
+ }
602
+
526
603
  // src/client/common/utils/logger.ts
527
604
  var getLogger = (verbose) => ({
528
605
  info: (...args) => console.info(...args),
@@ -534,14 +611,6 @@ var getLogger = (verbose) => ({
534
611
  // src/client/common/utils/userapi.ts
535
612
  import axios3 from "axios";
536
613
 
537
- // src/client/common/utils/helpers.ts
538
- import { extractChain, createPublicClient, createWalletClient, http, fallback } from "viem";
539
- import { sepolia as sepolia2 } from "viem/chains";
540
- import { privateKeyToAccount } from "viem/accounts";
541
-
542
- // src/client/common/constants.ts
543
- import { sepolia, mainnet } from "viem/chains";
544
-
545
614
  // src/client/common/utils/retry.ts
546
615
  import axios2 from "axios";
547
616
 
@@ -2037,44 +2106,78 @@ var ERC20_default = [
2037
2106
 
2038
2107
  // src/client/modules/billing/index.ts
2039
2108
  function createBillingModule(config) {
2040
- const { verbose = false, skipTelemetry = false, walletClient, publicClient, environment } = config;
2109
+ const { verbose = false, skipTelemetry = false, walletClient, publicClient, environment, privateKey } = config;
2041
2110
  if (!walletClient.account) {
2042
2111
  throw new Error("WalletClient must have an account attached");
2043
2112
  }
2044
2113
  const address = walletClient.account.address;
2045
2114
  const logger = getLogger(verbose);
2046
2115
  const billingEnvConfig = getBillingEnvironmentConfig(getBuildType());
2047
- const billingApi = new BillingApiClient(billingEnvConfig, walletClient);
2116
+ const billingApi = new BillingApiClient(billingEnvConfig, walletClient, { verbose });
2048
2117
  const environmentConfig = getEnvironmentConfig(environment);
2049
- const usdcCreditsAddress = environmentConfig.usdcCreditsAddress;
2050
- if (!usdcCreditsAddress) {
2118
+ if (!environmentConfig.usdcCreditsAddress) {
2051
2119
  throw new Error(`USDCCredits contract address not configured for environment "${environment}"`);
2052
2120
  }
2121
+ const usdcCreditsAddress = environmentConfig.usdcCreditsAddress;
2122
+ const baseUsdcCreditsAddress = environmentConfig.baseUsdcCreditsAddress;
2123
+ const baseRPCURL = environmentConfig.baseRPCURL;
2124
+ function resolveChainConfig(chain) {
2125
+ if (chain === "base") {
2126
+ if (!baseUsdcCreditsAddress || !baseRPCURL) {
2127
+ throw new Error(`Base chain not configured for environment "${environment}"`);
2128
+ }
2129
+ if (!privateKey) {
2130
+ throw new Error("Private key required for Base chain transactions");
2131
+ }
2132
+ const baseClients = createClients({
2133
+ privateKey,
2134
+ rpcUrl: baseRPCURL,
2135
+ chainId: BigInt(BASE_SEPOLIA_CHAIN_ID)
2136
+ });
2137
+ return {
2138
+ pub: baseClients.publicClient,
2139
+ wallet: baseClients.walletClient,
2140
+ creditsAddress: baseUsdcCreditsAddress,
2141
+ envConfig: {
2142
+ ...environmentConfig,
2143
+ chainID: BigInt(BASE_SEPOLIA_CHAIN_ID),
2144
+ defaultRPCURL: baseRPCURL
2145
+ }
2146
+ };
2147
+ }
2148
+ return {
2149
+ pub: publicClient,
2150
+ wallet: walletClient,
2151
+ creditsAddress: usdcCreditsAddress,
2152
+ envConfig: environmentConfig
2153
+ };
2154
+ }
2053
2155
  const module = {
2054
2156
  address,
2055
- async getTopUpInfo() {
2056
- const usdcAddress = await publicClient.readContract({
2057
- address: usdcCreditsAddress,
2157
+ async getTopUpInfo(opts) {
2158
+ const { pub, creditsAddress } = resolveChainConfig(opts?.chain);
2159
+ const usdcAddress = await pub.readContract({
2160
+ address: creditsAddress,
2058
2161
  abi: USDCCredits_default,
2059
2162
  functionName: "usdc"
2060
2163
  });
2061
2164
  const [minimumPurchase, usdcBalance, currentAllowance] = await Promise.all([
2062
- publicClient.readContract({
2063
- address: usdcCreditsAddress,
2165
+ pub.readContract({
2166
+ address: creditsAddress,
2064
2167
  abi: USDCCredits_default,
2065
2168
  functionName: "minimumPurchase"
2066
2169
  }),
2067
- publicClient.readContract({
2170
+ pub.readContract({
2068
2171
  address: usdcAddress,
2069
2172
  abi: ERC20_default,
2070
2173
  functionName: "balanceOf",
2071
2174
  args: [address]
2072
2175
  }),
2073
- publicClient.readContract({
2176
+ pub.readContract({
2074
2177
  address: usdcAddress,
2075
2178
  abi: ERC20_default,
2076
2179
  functionName: "allowance",
2077
- args: [address, usdcCreditsAddress]
2180
+ args: [address, creditsAddress]
2078
2181
  })
2079
2182
  ]);
2080
2183
  return { usdcAddress, minimumPurchase, usdcBalance, currentAllowance };
@@ -2084,11 +2187,12 @@ function createBillingModule(config) {
2084
2187
  {
2085
2188
  functionName: "topUp",
2086
2189
  skipTelemetry,
2087
- properties: { amount: opts.amount.toString() }
2190
+ properties: { amount: opts.amount.toString(), chain: opts.chain || "ethereum" }
2088
2191
  },
2089
2192
  async () => {
2090
2193
  const targetAccount = opts.account ?? address;
2091
- const { usdcAddress, currentAllowance } = await module.getTopUpInfo();
2194
+ const { pub, wallet, creditsAddress, envConfig } = resolveChainConfig(opts.chain);
2195
+ const { usdcAddress, currentAllowance } = await module.getTopUpInfo({ chain: opts.chain });
2092
2196
  const executions = [];
2093
2197
  if (currentAllowance < opts.amount) {
2094
2198
  executions.push({
@@ -2097,12 +2201,12 @@ function createBillingModule(config) {
2097
2201
  callData: encodeFunctionData3({
2098
2202
  abi: ERC20_default,
2099
2203
  functionName: "approve",
2100
- args: [usdcCreditsAddress, opts.amount]
2204
+ args: [creditsAddress, opts.amount]
2101
2205
  })
2102
2206
  });
2103
2207
  }
2104
2208
  executions.push({
2105
- target: usdcCreditsAddress,
2209
+ target: creditsAddress,
2106
2210
  value: 0n,
2107
2211
  callData: encodeFunctionData3({
2108
2212
  abi: USDCCredits_default,
@@ -2112,9 +2216,9 @@ function createBillingModule(config) {
2112
2216
  });
2113
2217
  const txHash = await executeBatch(
2114
2218
  {
2115
- walletClient,
2116
- publicClient,
2117
- environmentConfig,
2219
+ walletClient: wallet,
2220
+ publicClient: pub,
2221
+ environmentConfig: envConfig,
2118
2222
  executions,
2119
2223
  pendingMessage: "Submitting credit purchase..."
2120
2224
  },
@@ -2208,6 +2312,15 @@ function createBillingModule(config) {
2208
2312
  };
2209
2313
  }
2210
2314
  );
2315
+ },
2316
+ async getPaymentMethods() {
2317
+ return billingApi.getPaymentMethods();
2318
+ },
2319
+ async purchaseCredits(amountCents, paymentMethodId) {
2320
+ return billingApi.purchaseCredits(amountCents, paymentMethodId);
2321
+ },
2322
+ hasBaseSupport() {
2323
+ return !!baseUsdcCreditsAddress && !!baseRPCURL;
2211
2324
  }
2212
2325
  };
2213
2326
  return module;