@patchworkdev/pdk
Version:
Patchwork Development Kit
109 lines (94 loc) • 4.53 kB
text/typescript
import _ from 'lodash';
import path from 'path';
import { getFragmentRelationships, importABIFiles, importPatchworkConfig } from '../../common/helpers/config';
import { ErrorCode, PDKError } from '../../common/helpers/error';
import { formatAndSaveFile } from '../../common/helpers/file';
import { logger } from '../../common/helpers/logger';
import { envVarCase } from '../../common/helpers/text';
import LockFileManager from '../../services/lockFile';
import { Network } from '../../types';
export async function generateConfig(rootDir: string) {
// Define paths relative to the root dir
const configPath = path.join(rootDir, 'patchwork.config.ts');
const abiDir = path.join(rootDir, 'ponder', 'abis');
const ponderConfigPath = path.join(rootDir, 'ponder', 'ponder.config.ts');
const abis = await importABIFiles(abiDir);
const project = await importPatchworkConfig(configPath);
if (!project.networks) {
logger.error(`No networks found in the project config. Cannot build network configuration.`);
throw new PDKError(ErrorCode.PROJECT_CONFIG_MISSING_NETWORKS, `No networks found in the project config at ${configPath}`);
}
const lockFileManager = new LockFileManager(configPath);
const fragmentRelationships = getFragmentRelationships(project);
const entityEvents = ['Frozen', 'Locked', 'Transfer', 'Unlocked', 'Thawed'];
const imports: Set<string> = new Set();
// ToDo
// Need to add in the contract config for the Patchwork Protocol. Config needs to be added to the contracts array either before or after the entities
const contracts = Object.entries(project.contracts)
.map(([contractName, contractConfig]) => {
imports.add(contractName);
if (!project.networks) {
logger.warn(`No networks found. Cannot build contract config for ${contractName}`);
return '';
}
return contractTemplate(lockFileManager, contractName, project.networks);
})
.filter(Boolean);
const networks = Object.entries(project.networks).map(([networkName, network]) => {
return networkTemplate(networkName, network);
});
const config = configTemplate(imports, networks.join(), contracts.join());
await formatAndSaveFile(ponderConfigPath, config);
logger.info(`Ponder config generated successfully: ${ponderConfigPath}`);
}
function configTemplate(imports: Set<string>, networkConfig: string, contractConfig: string): string {
return `
import { createConfig, mergeAbis } from '@ponder/core';
import { Address, http } from 'viem';
import { ${Array.from(imports).join(', ')} } from './abis/index';
export default createConfig({
database:{
kind:"postgres",
connectionString:"postgres://postgres:password@postgres:5432/ponder"
},
networks: {
${networkConfig}
},
contracts: {
${contractConfig}
},
});
`;
}
// ToDo
// currently we don't allow for setting values as process.env.SOMETHING
// need to work out a way to do this as some runtime config for deployments
// should not be committed or be known ahead of time
export function networkTemplate(name: string, network: Network): string {
return ` ${name}: {
chainId: ${network.chain.id},
transport: http(process.env.${_.upperCase(name)}_RPC),
}`;
}
export function contractTemplate(lockFileManager: LockFileManager, name: string, network: Record<string, Network>): string {
return `${name}: {
network: {
${Object.entries(network)
.map(([networkName, network]) => contractNetworkTemplate(lockFileManager, name, networkName, network))
.filter((s) => s !== undefined)
.join(',')}
},
abi: mergeAbis([${name}]),
}`;
}
function contractNetworkTemplate(lockFileManager: LockFileManager, name: string, networkName: string, network: Network): string | undefined {
const deployment = lockFileManager.getLatestDeploymentForContract(name, networkName);
if (!deployment) {
logger.info(`No deployment found for ${name} on ${networkName} network`);
return undefined;
}
return `${networkName}: {
startBlock: Number(process.env.${envVarCase(name)}_BLOCK),
address: process.env.${envVarCase(name)}_ADDRESS as Address,
}`;
}