@layr-labs/ecloud-sdk 1.0.0-devep7 → 1.0.0
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/VERSION +2 -2
- package/dist/billing.cjs +164 -37
- package/dist/billing.cjs.map +1 -1
- package/dist/billing.d.cts +12 -3
- package/dist/billing.d.ts +12 -3
- package/dist/billing.js +164 -37
- package/dist/billing.js.map +1 -1
- package/dist/browser.cjs +1699 -139
- package/dist/browser.cjs.map +1 -1
- package/dist/browser.d.cts +5 -4
- package/dist/browser.d.ts +5 -4
- package/dist/browser.js +1699 -140
- package/dist/browser.js.map +1 -1
- package/dist/compute-B-V7Dbj9.d.cts +465 -0
- package/dist/compute-BJ_sqrKn.d.ts +465 -0
- package/dist/compute.cjs +1884 -735
- package/dist/compute.cjs.map +1 -1
- package/dist/compute.d.cts +3 -2
- package/dist/compute.d.ts +3 -2
- package/dist/compute.js +1873 -724
- package/dist/compute.js.map +1 -1
- package/dist/{helpers-B8KBOdM4.d.ts → helpers-CkcuSkNM.d.ts} +18 -191
- package/dist/{helpers-BVSe7yTf.d.cts → helpers-fmu7es2L.d.cts} +18 -191
- package/dist/{index-XhjPvHIY.d.cts → index-BVnxNfqb.d.cts} +67 -3
- package/dist/{index-XhjPvHIY.d.ts → index-BVnxNfqb.d.ts} +67 -3
- package/dist/index.cjs +2075 -744
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +73 -241
- package/dist/index.d.ts +73 -241
- package/dist/index.js +2054 -730
- package/dist/index.js.map +1 -1
- package/dist/validation-D3yIUF-Z.d.cts +167 -0
- package/dist/validation-D3yIUF-Z.d.ts +167 -0
- package/package.json +4 -5
- package/dist/compute-2WkiO-d8.d.ts +0 -194
- package/dist/compute-CoBGVJXh.d.cts +0 -194
- package/tools/ecloud-drain-watcher-linux-amd64 +0 -0
package/VERSION
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
version=1.0.0
|
|
2
|
-
commit=
|
|
1
|
+
version=1.0.0
|
|
2
|
+
commit=3f8023569b781e80105d1f06cbba82a8fb7dd3e0
|
package/dist/billing.cjs
CHANGED
|
@@ -332,6 +332,63 @@ var BillingApiClient = class {
|
|
|
332
332
|
return resp.json();
|
|
333
333
|
}
|
|
334
334
|
// ==========================================================================
|
|
335
|
+
// Admin - Coupon Methods
|
|
336
|
+
// ==========================================================================
|
|
337
|
+
async createCoupon(amountCents) {
|
|
338
|
+
const endpoint = `${this.config.billingApiServerURL}/admin/coupons`;
|
|
339
|
+
const resp = await this.makeAuthenticatedRequest(endpoint, "POST", "compute", { amountCents });
|
|
340
|
+
return resp.json();
|
|
341
|
+
}
|
|
342
|
+
async listCoupons(opts) {
|
|
343
|
+
const params = new URLSearchParams();
|
|
344
|
+
if (opts?.offset !== void 0) params.set("offset", opts.offset.toString());
|
|
345
|
+
if (opts?.limit !== void 0) params.set("limit", opts.limit.toString());
|
|
346
|
+
if (opts?.active !== void 0) params.set("active", opts.active.toString());
|
|
347
|
+
if (opts?.redeemed !== void 0) params.set("redeemed", opts.redeemed.toString());
|
|
348
|
+
const qs = params.toString();
|
|
349
|
+
const endpoint = `${this.config.billingApiServerURL}/admin/coupons${qs ? `?${qs}` : ""}`;
|
|
350
|
+
const resp = await this.makeAuthenticatedRequest(endpoint, "GET", "compute");
|
|
351
|
+
return resp.json();
|
|
352
|
+
}
|
|
353
|
+
async getCoupon(id) {
|
|
354
|
+
const endpoint = `${this.config.billingApiServerURL}/admin/coupons/${id}`;
|
|
355
|
+
const resp = await this.makeAuthenticatedRequest(endpoint, "GET", "compute");
|
|
356
|
+
return resp.json();
|
|
357
|
+
}
|
|
358
|
+
async deactivateCoupon(id) {
|
|
359
|
+
const endpoint = `${this.config.billingApiServerURL}/admin/coupons/${id}/deactivate`;
|
|
360
|
+
await this.makeAuthenticatedRequest(endpoint, "POST", "compute");
|
|
361
|
+
}
|
|
362
|
+
async redeemCouponForUser(id, address) {
|
|
363
|
+
const endpoint = `${this.config.billingApiServerURL}/admin/coupons/${id}/redeem`;
|
|
364
|
+
await this.makeAuthenticatedRequest(endpoint, "POST", "compute", { address });
|
|
365
|
+
}
|
|
366
|
+
// ==========================================================================
|
|
367
|
+
// Admin - Admin Management Methods
|
|
368
|
+
// ==========================================================================
|
|
369
|
+
async addAdmin(address) {
|
|
370
|
+
const endpoint = `${this.config.billingApiServerURL}/admin/admins`;
|
|
371
|
+
const resp = await this.makeAuthenticatedRequest(endpoint, "POST", "compute", { address });
|
|
372
|
+
return resp.json();
|
|
373
|
+
}
|
|
374
|
+
async removeAdmin(address) {
|
|
375
|
+
const endpoint = `${this.config.billingApiServerURL}/admin/admins/${address}`;
|
|
376
|
+
await this.makeAuthenticatedRequest(endpoint, "DELETE", "compute");
|
|
377
|
+
}
|
|
378
|
+
async listAdmins() {
|
|
379
|
+
const endpoint = `${this.config.billingApiServerURL}/admin/admins`;
|
|
380
|
+
const resp = await this.makeAuthenticatedRequest(endpoint, "GET", "compute");
|
|
381
|
+
return resp.json();
|
|
382
|
+
}
|
|
383
|
+
// ==========================================================================
|
|
384
|
+
// User - Coupon Redemption
|
|
385
|
+
// ==========================================================================
|
|
386
|
+
async redeemCoupon(code) {
|
|
387
|
+
const endpoint = `${this.config.billingApiServerURL}/v1/coupons/redeem`;
|
|
388
|
+
const resp = await this.makeAuthenticatedRequest(endpoint, "POST", "compute", { code });
|
|
389
|
+
return resp.json();
|
|
390
|
+
}
|
|
391
|
+
// ==========================================================================
|
|
335
392
|
// Internal Methods
|
|
336
393
|
// ==========================================================================
|
|
337
394
|
/**
|
|
@@ -463,6 +520,7 @@ Please check:
|
|
|
463
520
|
// src/client/common/config/environment.ts
|
|
464
521
|
var SEPOLIA_CHAIN_ID = 11155111;
|
|
465
522
|
var MAINNET_CHAIN_ID = 1;
|
|
523
|
+
var BASE_SEPOLIA_CHAIN_ID = 84532;
|
|
466
524
|
var CommonAddresses = {
|
|
467
525
|
ERC7702Delegator: "0x63c0c19a282a1b52b07dd5a65b58948a07dae32b"
|
|
468
526
|
};
|
|
@@ -482,27 +540,28 @@ var BILLING_ENVIRONMENTS = {
|
|
|
482
540
|
billingApiServerURL: "https://billingapi.eigencloud.xyz"
|
|
483
541
|
}
|
|
484
542
|
};
|
|
485
|
-
var PLATFORM_ENV_TESTNET_SEPOLIA = "testnet-sepolia";
|
|
486
|
-
var PLATFORM_ENV_MAINNET_ETHEREUM = "mainnet-ethereum";
|
|
487
|
-
var DEFAULT_APP_BASE_DOMAIN = "eigencloud.xyz";
|
|
488
543
|
var ENVIRONMENTS = {
|
|
489
544
|
"sepolia-dev": {
|
|
490
545
|
name: "sepolia",
|
|
491
546
|
build: "dev",
|
|
492
547
|
appControllerAddress: "0xa86DC1C47cb2518327fB4f9A1627F51966c83B92",
|
|
548
|
+
releaseAbiVersion: "v1.5",
|
|
549
|
+
// AppController upgraded to v1.5.x (containerPolicy)
|
|
493
550
|
permissionControllerAddress: ChainAddresses[SEPOLIA_CHAIN_ID].PermissionController,
|
|
494
551
|
erc7702DelegatorAddress: CommonAddresses.ERC7702Delegator,
|
|
495
552
|
kmsServerURL: "http://10.128.0.57:8080",
|
|
496
553
|
userApiServerURL: "https://userapi-compute-sepolia-dev.eigencloud.xyz",
|
|
497
554
|
defaultRPCURL: "https://ethereum-sepolia-rpc.publicnode.com",
|
|
498
555
|
usdcCreditsAddress: "0xbdA3897c3A428763B59015C64AB766c288C97376",
|
|
499
|
-
|
|
500
|
-
|
|
556
|
+
baseUsdcCreditsAddress: "0x7673a47463F80c6a3553Db9E54c8cDcd5313d0ac",
|
|
557
|
+
baseRPCURL: "https://base-sepolia-rpc.publicnode.com"
|
|
501
558
|
},
|
|
502
559
|
sepolia: {
|
|
503
560
|
name: "sepolia",
|
|
504
561
|
build: "prod",
|
|
505
562
|
appControllerAddress: "0x0dd810a6ffba6a9820a10d97b659f07d8d23d4E2",
|
|
563
|
+
releaseAbiVersion: "v1.4",
|
|
564
|
+
// prod still on AppController v1.4.0 (3-field Release)
|
|
506
565
|
permissionControllerAddress: ChainAddresses[SEPOLIA_CHAIN_ID].PermissionController,
|
|
507
566
|
erc7702DelegatorAddress: CommonAddresses.ERC7702Delegator,
|
|
508
567
|
kmsServerURL: "http://10.128.15.203:8080",
|
|
@@ -510,21 +569,21 @@ var ENVIRONMENTS = {
|
|
|
510
569
|
defaultRPCURL: "https://ethereum-sepolia-rpc.publicnode.com",
|
|
511
570
|
billingRPCURL: "https://ethereum-rpc.publicnode.com",
|
|
512
571
|
usdcCreditsAddress: "0xed9c88640ca9149Bd9f7ee6620074af10F2E145d",
|
|
513
|
-
|
|
514
|
-
|
|
572
|
+
baseUsdcCreditsAddress: "0x7673a47463F80c6a3553Db9E54c8cDcd5313d0ac",
|
|
573
|
+
baseRPCURL: "https://base-sepolia-rpc.publicnode.com"
|
|
515
574
|
},
|
|
516
575
|
"mainnet-alpha": {
|
|
517
576
|
name: "mainnet-alpha",
|
|
518
577
|
build: "prod",
|
|
519
578
|
appControllerAddress: "0xc38d35Fc995e75342A21CBd6D770305b142Fbe67",
|
|
579
|
+
releaseAbiVersion: "v1.4",
|
|
580
|
+
// prod still on AppController v1.4.0 (3-field Release)
|
|
520
581
|
permissionControllerAddress: ChainAddresses[MAINNET_CHAIN_ID].PermissionController,
|
|
521
582
|
erc7702DelegatorAddress: CommonAddresses.ERC7702Delegator,
|
|
522
583
|
kmsServerURL: "http://10.128.0.2:8080",
|
|
523
584
|
userApiServerURL: "https://userapi-compute.eigencloud.xyz",
|
|
524
585
|
defaultRPCURL: "https://ethereum-rpc.publicnode.com",
|
|
525
|
-
usdcCreditsAddress: "0xed9c88640ca9149Bd9f7ee6620074af10F2E145d"
|
|
526
|
-
platformEnv: PLATFORM_ENV_MAINNET_ETHEREUM,
|
|
527
|
-
appBaseDomain: DEFAULT_APP_BASE_DOMAIN
|
|
586
|
+
usdcCreditsAddress: "0xed9c88640ca9149Bd9f7ee6620074af10F2E145d"
|
|
528
587
|
}
|
|
529
588
|
};
|
|
530
589
|
var CHAIN_ID_TO_ENVIRONMENT = {
|
|
@@ -584,7 +643,7 @@ function getBillingEnvironmentConfig(build) {
|
|
|
584
643
|
};
|
|
585
644
|
}
|
|
586
645
|
function getBuildType() {
|
|
587
|
-
const buildTimeType = true ? "
|
|
646
|
+
const buildTimeType = true ? "prod"?.toLowerCase() : void 0;
|
|
588
647
|
const runtimeType = process.env.BUILD_TYPE?.toLowerCase();
|
|
589
648
|
const buildType = buildTimeType || runtimeType;
|
|
590
649
|
if (buildType === "dev") {
|
|
@@ -603,6 +662,41 @@ function isEnvironmentAvailable(environment) {
|
|
|
603
662
|
return getAvailableEnvironments().includes(environment);
|
|
604
663
|
}
|
|
605
664
|
|
|
665
|
+
// src/client/common/utils/helpers.ts
|
|
666
|
+
var import_viem2 = require("viem");
|
|
667
|
+
var import_chains2 = require("viem/chains");
|
|
668
|
+
var import_accounts = require("viem/accounts");
|
|
669
|
+
|
|
670
|
+
// src/client/common/constants.ts
|
|
671
|
+
var import_chains = require("viem/chains");
|
|
672
|
+
var SUPPORTED_CHAINS = [import_chains.mainnet, import_chains.sepolia, import_chains.baseSepolia];
|
|
673
|
+
|
|
674
|
+
// src/client/common/utils/helpers.ts
|
|
675
|
+
function getChainFromID(chainID, fallback2 = import_chains2.sepolia) {
|
|
676
|
+
const id = Number(chainID);
|
|
677
|
+
return (0, import_viem2.extractChain)({ chains: SUPPORTED_CHAINS, id }) || fallback2;
|
|
678
|
+
}
|
|
679
|
+
function createClients(options) {
|
|
680
|
+
const { privateKey, rpcUrl, chainId } = options;
|
|
681
|
+
const privateKeyHex = addHexPrefix(privateKey);
|
|
682
|
+
const account = (0, import_accounts.privateKeyToAccount)(privateKeyHex);
|
|
683
|
+
const chain = getChainFromID(chainId);
|
|
684
|
+
const transport = typeof rpcUrl === "string" ? (0, import_viem2.http)(rpcUrl) : (0, import_viem2.fallback)(rpcUrl.map((url) => (0, import_viem2.http)(url)));
|
|
685
|
+
const publicClient = (0, import_viem2.createPublicClient)({
|
|
686
|
+
chain,
|
|
687
|
+
transport
|
|
688
|
+
});
|
|
689
|
+
const walletClient = (0, import_viem2.createWalletClient)({
|
|
690
|
+
account,
|
|
691
|
+
chain,
|
|
692
|
+
transport
|
|
693
|
+
});
|
|
694
|
+
return { walletClient, publicClient };
|
|
695
|
+
}
|
|
696
|
+
function addHexPrefix(value) {
|
|
697
|
+
return value.startsWith("0x") ? value : `0x${value}`;
|
|
698
|
+
}
|
|
699
|
+
|
|
606
700
|
// src/client/common/utils/logger.ts
|
|
607
701
|
var getLogger = (verbose) => ({
|
|
608
702
|
info: (...args) => console.info(...args),
|
|
@@ -614,14 +708,6 @@ var getLogger = (verbose) => ({
|
|
|
614
708
|
// src/client/common/utils/userapi.ts
|
|
615
709
|
var import_axios3 = __toESM(require("axios"), 1);
|
|
616
710
|
|
|
617
|
-
// src/client/common/utils/helpers.ts
|
|
618
|
-
var import_viem2 = require("viem");
|
|
619
|
-
var import_chains2 = require("viem/chains");
|
|
620
|
-
var import_accounts = require("viem/accounts");
|
|
621
|
-
|
|
622
|
-
// src/client/common/constants.ts
|
|
623
|
-
var import_chains = require("viem/chains");
|
|
624
|
-
|
|
625
711
|
// src/client/common/utils/retry.ts
|
|
626
712
|
var import_axios2 = __toESM(require("axios"), 1);
|
|
627
713
|
|
|
@@ -2117,7 +2203,7 @@ var ERC20_default = [
|
|
|
2117
2203
|
|
|
2118
2204
|
// src/client/modules/billing/index.ts
|
|
2119
2205
|
function createBillingModule(config) {
|
|
2120
|
-
const { verbose = false, skipTelemetry = false, walletClient, publicClient, environment } = config;
|
|
2206
|
+
const { verbose = false, skipTelemetry = false, walletClient, publicClient, environment, privateKey } = config;
|
|
2121
2207
|
if (!walletClient.account) {
|
|
2122
2208
|
throw new Error("WalletClient must have an account attached");
|
|
2123
2209
|
}
|
|
@@ -2126,35 +2212,69 @@ function createBillingModule(config) {
|
|
|
2126
2212
|
const billingEnvConfig = getBillingEnvironmentConfig(getBuildType());
|
|
2127
2213
|
const billingApi = new BillingApiClient(billingEnvConfig, walletClient, { verbose });
|
|
2128
2214
|
const environmentConfig = getEnvironmentConfig(environment);
|
|
2129
|
-
|
|
2130
|
-
if (!usdcCreditsAddress) {
|
|
2215
|
+
if (!environmentConfig.usdcCreditsAddress) {
|
|
2131
2216
|
throw new Error(`USDCCredits contract address not configured for environment "${environment}"`);
|
|
2132
2217
|
}
|
|
2218
|
+
const usdcCreditsAddress = environmentConfig.usdcCreditsAddress;
|
|
2219
|
+
const baseUsdcCreditsAddress = environmentConfig.baseUsdcCreditsAddress;
|
|
2220
|
+
const baseRPCURL = environmentConfig.baseRPCURL;
|
|
2221
|
+
function resolveChainConfig(chain) {
|
|
2222
|
+
if (chain === "base") {
|
|
2223
|
+
if (!baseUsdcCreditsAddress || !baseRPCURL) {
|
|
2224
|
+
throw new Error(`Base chain not configured for environment "${environment}"`);
|
|
2225
|
+
}
|
|
2226
|
+
if (!privateKey) {
|
|
2227
|
+
throw new Error("Private key required for Base chain transactions");
|
|
2228
|
+
}
|
|
2229
|
+
const baseClients = createClients({
|
|
2230
|
+
privateKey,
|
|
2231
|
+
rpcUrl: baseRPCURL,
|
|
2232
|
+
chainId: BigInt(BASE_SEPOLIA_CHAIN_ID)
|
|
2233
|
+
});
|
|
2234
|
+
return {
|
|
2235
|
+
pub: baseClients.publicClient,
|
|
2236
|
+
wallet: baseClients.walletClient,
|
|
2237
|
+
creditsAddress: baseUsdcCreditsAddress,
|
|
2238
|
+
envConfig: {
|
|
2239
|
+
...environmentConfig,
|
|
2240
|
+
chainID: BigInt(BASE_SEPOLIA_CHAIN_ID),
|
|
2241
|
+
defaultRPCURL: baseRPCURL
|
|
2242
|
+
}
|
|
2243
|
+
};
|
|
2244
|
+
}
|
|
2245
|
+
return {
|
|
2246
|
+
pub: publicClient,
|
|
2247
|
+
wallet: walletClient,
|
|
2248
|
+
creditsAddress: usdcCreditsAddress,
|
|
2249
|
+
envConfig: environmentConfig
|
|
2250
|
+
};
|
|
2251
|
+
}
|
|
2133
2252
|
const module2 = {
|
|
2134
2253
|
address,
|
|
2135
|
-
async getTopUpInfo() {
|
|
2136
|
-
const
|
|
2137
|
-
|
|
2254
|
+
async getTopUpInfo(opts) {
|
|
2255
|
+
const { pub, creditsAddress } = resolveChainConfig(opts?.chain);
|
|
2256
|
+
const usdcAddress = await pub.readContract({
|
|
2257
|
+
address: creditsAddress,
|
|
2138
2258
|
abi: USDCCredits_default,
|
|
2139
2259
|
functionName: "usdc"
|
|
2140
2260
|
});
|
|
2141
2261
|
const [minimumPurchase, usdcBalance, currentAllowance] = await Promise.all([
|
|
2142
|
-
|
|
2143
|
-
address:
|
|
2262
|
+
pub.readContract({
|
|
2263
|
+
address: creditsAddress,
|
|
2144
2264
|
abi: USDCCredits_default,
|
|
2145
2265
|
functionName: "minimumPurchase"
|
|
2146
2266
|
}),
|
|
2147
|
-
|
|
2267
|
+
pub.readContract({
|
|
2148
2268
|
address: usdcAddress,
|
|
2149
2269
|
abi: ERC20_default,
|
|
2150
2270
|
functionName: "balanceOf",
|
|
2151
2271
|
args: [address]
|
|
2152
2272
|
}),
|
|
2153
|
-
|
|
2273
|
+
pub.readContract({
|
|
2154
2274
|
address: usdcAddress,
|
|
2155
2275
|
abi: ERC20_default,
|
|
2156
2276
|
functionName: "allowance",
|
|
2157
|
-
args: [address,
|
|
2277
|
+
args: [address, creditsAddress]
|
|
2158
2278
|
})
|
|
2159
2279
|
]);
|
|
2160
2280
|
return { usdcAddress, minimumPurchase, usdcBalance, currentAllowance };
|
|
@@ -2164,11 +2284,12 @@ function createBillingModule(config) {
|
|
|
2164
2284
|
{
|
|
2165
2285
|
functionName: "topUp",
|
|
2166
2286
|
skipTelemetry,
|
|
2167
|
-
properties: { amount: opts.amount.toString() }
|
|
2287
|
+
properties: { amount: opts.amount.toString(), chain: opts.chain || "ethereum" }
|
|
2168
2288
|
},
|
|
2169
2289
|
async () => {
|
|
2170
2290
|
const targetAccount = opts.account ?? address;
|
|
2171
|
-
const {
|
|
2291
|
+
const { pub, wallet, creditsAddress, envConfig } = resolveChainConfig(opts.chain);
|
|
2292
|
+
const { usdcAddress, currentAllowance } = await module2.getTopUpInfo({ chain: opts.chain });
|
|
2172
2293
|
const executions = [];
|
|
2173
2294
|
if (currentAllowance < opts.amount) {
|
|
2174
2295
|
executions.push({
|
|
@@ -2177,12 +2298,12 @@ function createBillingModule(config) {
|
|
|
2177
2298
|
callData: (0, import_viem5.encodeFunctionData)({
|
|
2178
2299
|
abi: ERC20_default,
|
|
2179
2300
|
functionName: "approve",
|
|
2180
|
-
args: [
|
|
2301
|
+
args: [creditsAddress, opts.amount]
|
|
2181
2302
|
})
|
|
2182
2303
|
});
|
|
2183
2304
|
}
|
|
2184
2305
|
executions.push({
|
|
2185
|
-
target:
|
|
2306
|
+
target: creditsAddress,
|
|
2186
2307
|
value: 0n,
|
|
2187
2308
|
callData: (0, import_viem5.encodeFunctionData)({
|
|
2188
2309
|
abi: USDCCredits_default,
|
|
@@ -2192,9 +2313,9 @@ function createBillingModule(config) {
|
|
|
2192
2313
|
});
|
|
2193
2314
|
const txHash = await executeBatch(
|
|
2194
2315
|
{
|
|
2195
|
-
walletClient,
|
|
2196
|
-
publicClient,
|
|
2197
|
-
environmentConfig,
|
|
2316
|
+
walletClient: wallet,
|
|
2317
|
+
publicClient: pub,
|
|
2318
|
+
environmentConfig: envConfig,
|
|
2198
2319
|
executions,
|
|
2199
2320
|
pendingMessage: "Submitting credit purchase..."
|
|
2200
2321
|
},
|
|
@@ -2294,6 +2415,12 @@ function createBillingModule(config) {
|
|
|
2294
2415
|
},
|
|
2295
2416
|
async purchaseCredits(amountCents, paymentMethodId) {
|
|
2296
2417
|
return billingApi.purchaseCredits(amountCents, paymentMethodId);
|
|
2418
|
+
},
|
|
2419
|
+
hasBaseSupport() {
|
|
2420
|
+
return !!baseUsdcCreditsAddress && !!baseRPCURL;
|
|
2421
|
+
},
|
|
2422
|
+
async redeemCoupon(code) {
|
|
2423
|
+
return billingApi.redeemCoupon(code);
|
|
2297
2424
|
}
|
|
2298
2425
|
};
|
|
2299
2426
|
return module2;
|