This repository has been archived by the owner on Jan 24, 2024. It is now read-only.
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(studio): Add Viem multicall dataloader and CLI for contract fact…
…ory (#3021)
- Loading branch information
1 parent
1146d68
commit 299f02d
Showing
91 changed files
with
8,585 additions
and
4,677 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
86 changes: 86 additions & 0 deletions
86
cli/commands/generate-contract-factory/generate-ethers-contract-factory.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
/* eslint no-console: 0 */ | ||
import path from 'path'; | ||
|
||
import { writeFileSync } from 'fs-extra'; | ||
import { camelCase, sortBy, upperFirst } from 'lodash'; | ||
|
||
import { getAbis } from './get-abis'; | ||
|
||
export const generateEthersContractFactory = async (location: string) => { | ||
const abis = sortBy(await getAbis(location)); | ||
const factoryName = upperFirst(camelCase(path.basename(location))); | ||
const isRoot = path.basename(location) === 'contract'; | ||
const factoryFullName = isRoot ? 'ContractFactory' : `${factoryName}ContractFactory`; | ||
|
||
const renderer = { | ||
ethers: async () => { | ||
const imports = abis.flatMap(abi => { | ||
const typeName = upperFirst(camelCase(abi)); | ||
return [`import { ${typeName}__factory } from './ethers';`, `import type { ${typeName} } from './ethers';`]; | ||
}); | ||
|
||
const factoryMethods = abis.map(abi => { | ||
const methodName = camelCase(abi); | ||
const typeName = upperFirst(methodName); | ||
return `${methodName}({address, network}: ContractOpts) { return ${typeName}__factory.connect(address, ${ | ||
isRoot ? 'this.networkProviderResolver(network)' : 'this.appToolkit.getNetworkProvider(network)' | ||
}); }`; | ||
}); | ||
|
||
const interfaceRows = abis.map(abi => { | ||
const methodName = camelCase(abi); | ||
const typeName = upperFirst(methodName); | ||
return `${methodName}(opts: ContractOpts): ${typeName};`; | ||
}); | ||
|
||
const reexports = abis.map(abi => { | ||
const typeName = upperFirst(camelCase(abi)); | ||
return [`export type { ${typeName} } from './ethers'`]; | ||
}); | ||
|
||
writeFileSync( | ||
path.join(location, `/contracts/ethers.contract-factory.ts`), | ||
` | ||
import { Injectable } from '@nestjs/common'; | ||
import { Inject } from '@nestjs/common'; | ||
import { StaticJsonRpcProvider } from '@ethersproject/providers'; | ||
import { IAppToolkit, APP_TOOLKIT } from '~app-toolkit/app-toolkit.interface'; | ||
import { NetworkProviderService } from '~network-provider/network-provider.service'; | ||
import { Network } from '~types/network.interface'; | ||
${imports.join('\n')} | ||
${isRoot ? '' : "import { ContractFactory } from '~contract/contracts'"} | ||
type ContractOpts = {address: string, network: Network}; | ||
${!isRoot ? '' : 'type NetworkProviderResolver = (network: Network) => StaticJsonRpcProvider;'} | ||
${ | ||
isRoot | ||
? ` | ||
export interface IContractFactory { | ||
${interfaceRows.join('\n')} | ||
} | ||
` | ||
: '' | ||
} | ||
@Injectable() | ||
export class ${factoryFullName} ${isRoot ? 'implements IContractFactory' : 'extends ContractFactory'} { | ||
constructor(${ | ||
isRoot | ||
? 'protected readonly networkProviderResolver: NetworkProviderResolver' | ||
: '@Inject(APP_TOOLKIT) protected readonly appToolkit: IAppToolkit' | ||
}) { ${isRoot ? '' : 'super((network: Network) => appToolkit.getNetworkProvider(network));'} } | ||
${factoryMethods.join('\n')} | ||
} | ||
${reexports.join('\n')} | ||
`, | ||
); | ||
}, | ||
}; | ||
|
||
await renderer.ethers(); | ||
}; |
31 changes: 31 additions & 0 deletions
31
cli/commands/generate-contract-factory/generate-ethers-contract.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
/* eslint no-console: 0 */ | ||
import fs from 'fs'; | ||
import path from 'path'; | ||
import util from 'util'; | ||
|
||
import { glob, runTypeChain } from 'typechain'; | ||
|
||
const mkdir = util.promisify(fs.mkdir); | ||
const rmdir = util.promisify(fs.rm); | ||
const exists = util.promisify(fs.exists); | ||
|
||
export const generateEthersContract = async (location: string) => { | ||
const providerDir = path.join(location, `/contracts/ethers`); | ||
const providerDirExists = await exists(providerDir); | ||
if (providerDirExists) { | ||
await rmdir(providerDir, { recursive: true }); | ||
await mkdir(providerDir, { recursive: true }); | ||
} | ||
|
||
const cwd = process.cwd(); | ||
const allFiles = glob(cwd, [path.join(location, '/contracts/abis/*.json')]); | ||
if (!allFiles.length) return; | ||
|
||
await runTypeChain({ | ||
cwd, | ||
filesToProcess: allFiles, | ||
allFiles, | ||
outDir: providerDir, | ||
target: 'ethers-v5', | ||
}); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
/* eslint no-console: 0 */ | ||
import fs, { writeFileSync } from 'fs'; | ||
import path from 'path'; | ||
import util from 'util'; | ||
|
||
const exists = util.promisify(fs.exists); | ||
|
||
export const generateIndex = async (location: string) => { | ||
let content = ` | ||
/* Autogenerated file. Do not edit manually. */ | ||
/* tslint:disable */ | ||
/* eslint-disable */ | ||
`; | ||
|
||
if (await exists(path.join(location, `/contracts/ethers.contract-factory.ts`))) { | ||
content += `export * from './ethers.contract-factory';\n`; | ||
} | ||
|
||
if (await exists(path.join(location, `/contracts/viem.contract-factory.ts`))) { | ||
content += `export * from './viem.contract-factory';\n`; | ||
} | ||
|
||
writeFileSync(path.join(location, `/contracts/index.ts`), content); | ||
}; |
Oops, something went wrong.