Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
119 changes: 119 additions & 0 deletions e2e/src/e2e.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,14 @@ import {
} from './helper/tests';
import { init } from './init';

const RPC_OVERRIDE = process.env['LIT_YELLOWSTONE_PRIVATE_RPC_URL'];
if (RPC_OVERRIDE) {
console.log(
'🧪 E2E: Using RPC override (LIT_YELLOWSTONE_PRIVATE_RPC_URL):',
RPC_OVERRIDE
);
}

describe('all', () => {
// Singleton baby
let ctx: Awaited<ReturnType<typeof init>>;
Expand Down Expand Up @@ -161,3 +169,114 @@ describe('all', () => {
});
});
});

describe('rpc override', () => {
const TEST_RPC = process.env.LIT_YELLOWSTONE_PRIVATE_RPC_URL;
// const TEST_RPC = 'https://yellowstone-override.example';

// beforeAll(() => {
// process.env.LIT_YELLOWSTONE_PRIVATE_RPC_URL = TEST_RPC;
// });

// afterAll(() => {
// process.env.LIT_YELLOWSTONE_PRIVATE_RPC_URL = ORIGINAL_RPC;
// });

it('applies env rpc override to module and client', async () => {
const networks = await import('@lit-protocol/networks');

// choose module by NETWORK env (same way init.ts does)
const network = process.env.NETWORK || 'naga-dev';
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are several places that do this, we will optimise in a follow up PR.

const importNameMap: Record<string, string> = {
'naga-dev': 'nagaDev',
'naga-test': 'nagaTest',
'naga-local': 'nagaLocal',
'naga-staging': 'nagaStaging',
};
const importName = importNameMap[network];
const baseModule: any = (networks as any)[importName];

// apply override
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks confusing but purely for observability / checking the logs to see if they are correctly applied.

const mod =
typeof baseModule.withOverrides === 'function'
? baseModule.withOverrides({ rpcUrl: TEST_RPC })
: baseModule;

// log for verification
// base vs effective (when override is supported)
const baseRpcUrl =
typeof baseModule.getRpcUrl === 'function'
? baseModule.getRpcUrl()
: 'n/a';
const effRpcUrl =
typeof mod.getRpcUrl === 'function' ? mod.getRpcUrl() : 'n/a';
// eslint-disable-next-line no-console
console.log('[rpc-override] TEST_RPC:', TEST_RPC);
// eslint-disable-next-line no-console
console.log(
'[rpc-override] module rpc (base → effective):',
baseRpcUrl,
'→',
effRpcUrl
);
try {
const baseChain =
typeof baseModule.getChainConfig === 'function'
? baseModule.getChainConfig()
: null;
const effChain =
typeof mod.getChainConfig === 'function' ? mod.getChainConfig() : null;
if (baseChain && effChain) {
// eslint-disable-next-line no-console
console.log(
'[rpc-override] module chain id/name (base → effective):',
`${baseChain.id}/${baseChain.name}`,
'→',
`${effChain.id}/${effChain.name}`
);
// eslint-disable-next-line no-console
console.log(
'[rpc-override] module rpcUrls.default.http (base → effective):',
baseChain.rpcUrls.default.http,
'→',
effChain.rpcUrls.default.http
);
// eslint-disable-next-line no-console
console.log(
'[rpc-override] module rpcUrls.public.http (base → effective):',
(baseChain.rpcUrls as any)['public']?.http,
'→',
(effChain.rpcUrls as any)['public']?.http
);
}
} catch {}

// module reflects override
expect(mod.getRpcUrl()).toBe(TEST_RPC);
const chain = mod.getChainConfig();
expect(chain.rpcUrls.default.http[0]).toBe(TEST_RPC);
expect((chain.rpcUrls as any)['public'].http[0]).toBe(TEST_RPC);

// client reflects override
const { createLitClient } = await import('@lit-protocol/lit-client');
const client = await createLitClient({ network: mod });
const cc = client.getChainConfig();

// eslint-disable-next-line no-console
console.log('[rpc-override] client rpcUrl:', cc.rpcUrl);
// eslint-disable-next-line no-console
console.log(
'[rpc-override] client viem rpcUrls.default:',
cc.viemConfig.rpcUrls.default.http
);
// eslint-disable-next-line no-console
console.log(
'[rpc-override] client viem rpcUrls.public:',
(cc.viemConfig.rpcUrls as any)['public']?.http
);

expect(cc.rpcUrl).toBe(TEST_RPC);
expect(cc.viemConfig.rpcUrls.default.http[0]).toBe(TEST_RPC);
expect((cc.viemConfig.rpcUrls as any)['public'].http[0]).toBe(TEST_RPC);
});
});
16 changes: 15 additions & 1 deletion e2e/src/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,21 @@ export const init = async (

// Dynamic import of network module
const networksModule = await import('@lit-protocol/networks');
const _networkModule = networksModule[config.importName];
const _baseNetworkModule = networksModule[config.importName];

// Optional RPC override from env
const rpcOverride = process.env['LIT_YELLOWSTONE_PRIVATE_RPC_URL'];
const _networkModule =
rpcOverride && typeof _baseNetworkModule.withOverrides === 'function'
? _baseNetworkModule.withOverrides({ rpcUrl: rpcOverride })
: _baseNetworkModule;

if (rpcOverride) {
console.log(
'✅ Using RPC override (LIT_YELLOWSTONE_PRIVATE_RPC_URL):',
rpcOverride
);
}

// Fund accounts based on network type
const isLocal = config.type === 'local';
Expand Down
24 changes: 22 additions & 2 deletions packages/auth-services/src/_setup/initSystemContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,13 @@ declare global {
};
}

export async function initSystemContext({ appName }: { appName: string }) {
export async function initSystemContext({
appName,
rpcUrl,
}: {
appName: string;
rpcUrl?: string;
}) {
console.log('🔥 [initSystemContext] Initializing system context...');

let networkModule: any;
Expand All @@ -34,8 +40,22 @@ export async function initSystemContext({ appName }: { appName: string }) {
throw new Error(`Unsupported network: ${env.NETWORK}`);
}

const overrideRpc = rpcUrl || env.LIT_TXSENDER_RPC_URL;

// Apply runtime override if rpcUrl provided
const effectiveModule =
overrideRpc && typeof networkModule.withOverrides === 'function'
? networkModule.withOverrides({ rpcUrl: overrideRpc })
: networkModule;

try {
const baseRpc = typeof networkModule.getRpcUrl === 'function' ? networkModule.getRpcUrl() : 'n/a';
const effRpc = typeof effectiveModule.getRpcUrl === 'function' ? effectiveModule.getRpcUrl() : 'n/a';
console.log('[initSystemContext] RPC (base → effective):', baseRpc, '→', effRpc);
} catch {}

const litClient = await createLitClient({
network: networkModule,
network: effectiveModule,
});

const account = privateKeyToAccount(env.LIT_TXSENDER_PRIVATE_KEY as Hex);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,10 @@ export const createLitAuthServer = (
// =============================================================
// Ensure system context is initialized before server fully starts, using appName from config
// This was originally at the top level, moved here to use config.appName
await initSystemContext({ appName: config.appName });
await initSystemContext({
appName: config.appName,
rpcUrl: config.litTxsenderRpcUrl,
});
})
.get('/', () => ({
message: 'PKP Auth Service is running. PKP minting is now asynchronous.',
Expand Down
3 changes: 2 additions & 1 deletion packages/auth-services/src/queue-manager/worker.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { initSystemContext } from '../_setup/initSystemContext';
import { bullmqConnectionOptions, mainQueueName } from './src/bullmqSetup';
import { createGenericWorker } from './src/genericWorker';
import { env } from '../env';

interface ParsedRedisConnectionOpts {
host?: string;
Expand All @@ -10,7 +11,7 @@ interface ParsedRedisConnectionOpts {
}

export async function startAuthServiceWorker() {
await initSystemContext({ appName: 'auth-services-worker' });
await initSystemContext({ appName: 'auth-services-worker', rpcUrl: env.LIT_TXSENDER_RPC_URL });
console.log('------------------------------------------------------');
console.log(' Attempting to start Generic BullMQ Worker Process... ');
console.log('------------------------------------------------------');
Expand Down
6 changes: 3 additions & 3 deletions packages/lit-client/src/lib/LitClient/createLitClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ import {
} from '@lit-protocol/access-control-conditions';
import { encrypt as blsEncrypt } from '@lit-protocol/crypto';
import { getChildLogger } from '@lit-protocol/logger';
import type {
LitNetworkModule,
PKPStorageProvider,
import {
type LitNetworkModule,
type PKPStorageProvider,
} from '@lit-protocol/networks';
import {
AuthContextSchema2,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,16 +120,14 @@ export async function createPKPViemAccount({
tx,
address,
chain,
transportUrl,
}: {
tx: Partial<TransactionSerializable>;
address: `0x${string}`;
chain: Chain;
transportUrl: string;
}): Promise<TransactionSerializable> {
const client = createPublicClient({
chain,
transport: http(transportUrl),
transport: http(chain.rpcUrls.default.http[0]),
});

try {
Expand Down Expand Up @@ -246,7 +244,6 @@ export async function createPKPViemAccount({
tx: txRequest,
address,
chain: chainConfig,
transportUrl: chainConfig.rpcUrls.default.http[0],
});
} else {
// Ensure minimum required fields for transaction type inference
Expand Down
24 changes: 24 additions & 0 deletions packages/networks/src/chains/ChronicleYellowstone.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,27 @@ export const WagmiConfig = createConfig({
[viemChainConfig.id]: http(),
},
});

/**
* Resolve the effective RPC URL from an optional override.
*/
export function resolveRpcUrl(overrideRpc?: string): string {
return overrideRpc ?? RPC_URL;
}

/**
* Build a Chain config using the base Chronicle Yellowstone config,
* applying an optional RPC override to both default and public http URLs.
*/
export function buildViemChainConfig(overrideRpc?: string): Chain {
const rpc = resolveRpcUrl(overrideRpc);
const base = viemChainConfig;
return {
...base,
rpcUrls: {
...base.rpcUrls,
default: { ...base.rpcUrls.default, http: [rpc] },
public: { ...(base.rpcUrls as any)['public'], http: [rpc] },
},
} as Chain;
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export interface BaseEnvironmentOptions<T, M> {
minimumThreshold?: number;
httpProtocol?: 'http://' | 'https://';
requiredAttestation?: boolean;
rpcUrlOverride?: string;
}

export abstract class BaseNetworkEnvironment<T, M> {
Expand All @@ -24,9 +25,9 @@ export abstract class BaseNetworkEnvironment<T, M> {
this.config = {
minimumThreshold: options.minimumThreshold || 3,
network: options.network,
rpcUrl: this.getRpcUrl(),
rpcUrl: this.getRpcUrl(options.rpcUrlOverride),
abiSignatures: options.abiSignatures,
chainConfig: this.getChainConfig(),
chainConfig: this.getChainConfig(options.rpcUrlOverride),
httpProtocol: options.httpProtocol || 'https://',
networkSpecificConfigs: options.networkSpecificConfigs,
endpoints: this.getEndpoints(),
Expand All @@ -51,8 +52,8 @@ export abstract class BaseNetworkEnvironment<T, M> {
return this.config.services;
}

protected abstract getRpcUrl(): string;
protected abstract getChainConfig(): Chain;
protected abstract getRpcUrl(overrideRpc?: string): string;
protected abstract getChainConfig(overrideRpc?: string): Chain;
protected abstract getEndpoints(): NagaEndpointsType;
protected abstract getDefaultRealmId(): bigint;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export class NagaDevEnvironment extends BaseNetworkEnvironment<
NagaDevSignatures,
NagaDevSpecificConfigs
> {
constructor() {
constructor(options?: { rpcUrlOverride?: string }) {
super({
network: NETWORK,
abiSignatures: nagaDevSignatures,
Expand All @@ -34,15 +34,16 @@ export class NagaDevEnvironment extends BaseNetworkEnvironment<
minimumThreshold: MINIMUM_THRESHOLD,
httpProtocol: PROTOCOL,
requiredAttestation: false,
rpcUrlOverride: options?.rpcUrlOverride,
});
}

protected getRpcUrl(): string {
return chainInfo.RPC_URL;
protected getRpcUrl(overrideRpc?: string): string {
return chainInfo.resolveRpcUrl(overrideRpc);
}

protected getChainConfig(): Chain {
return chainInfo.viemChainConfig;
protected getChainConfig(overrideRpc?: string): Chain {
return chainInfo.buildViemChainConfig(overrideRpc);
}

protected getEndpoints(): NagaEndpointsType {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export class NagaLocalEnvironment extends BaseNetworkEnvironment<
NagaLocalSignatures,
NagaLocalSpecificConfigs
> {
constructor() {
constructor(options?: { rpcUrlOverride?: string }) {
super({
network: NETWORK,
abiSignatures: signatures, // Note: Uses locally generated signatures
Expand All @@ -36,15 +36,25 @@ export class NagaLocalEnvironment extends BaseNetworkEnvironment<
minimumThreshold: MINIMUM_THRESHOLD,
httpProtocol: PROTOCOL, // Note: HTTP not HTTPS
requiredAttestation: false,
rpcUrlOverride: options?.rpcUrlOverride,
});
}

protected getRpcUrl(): string {
return chainInfo.RPC_URL; // Note: Uses Anvil instead of ChronicleYellowstone
protected getRpcUrl(overrideRpc?: string): string {
return overrideRpc ?? chainInfo.RPC_URL; // Note: Uses Anvil instead of ChronicleYellowstone
}

protected getChainConfig(): Chain {
return chainInfo.viemChainConfig; // Note: Anvil chain config
protected getChainConfig(overrideRpc?: string): Chain {
const rpc = overrideRpc ?? chainInfo.RPC_URL;
const base = chainInfo.viemChainConfig; // Note: Anvil chain config
return {
...base,
rpcUrls: {
...base.rpcUrls,
default: { ...base.rpcUrls.default, http: [rpc] },
public: { ...(base.rpcUrls as any)['public'], http: [rpc] },
},
} as Chain;
}

protected getEndpoints(): NagaEndpointsType {
Expand Down
Loading
Loading