-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Vendor Safe Deployments at Build Time (#61)
- Loading branch information
Showing
9 changed files
with
2,086 additions
and
111 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 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,82 @@ | ||
import { | ||
getProxyFactoryDeployment, | ||
getSafeL2SingletonDeployment, | ||
} from "@safe-global/safe-deployments"; | ||
import { | ||
getSafe4337ModuleDeployment, | ||
getSafeModuleSetupDeployment, | ||
} from "@safe-global/safe-modules-deployments"; | ||
import { Address, parseAbi } from "viem"; | ||
|
||
import { Deployment, SafeDeployments } from "../src/types"; | ||
import { getClient } from "../src/util"; | ||
|
||
// Define the deployment version and chain ID (e.g., "1.4.1" for Safe contracts, "0.3.0" for modules) | ||
export const SAFE_VERSION = "1.4.1"; | ||
export const MODULE_VERSION = "0.3.0"; | ||
|
||
type DeploymentFn = (filter?: { | ||
version: string; | ||
}) => | ||
| { networkAddresses: { [chainId: string]: string }; abi: unknown[] } | ||
| undefined; | ||
|
||
type DeploymentArgs = { version: string }; | ||
|
||
export async function getDeployment( | ||
fn: DeploymentFn, | ||
{ version }: DeploymentArgs | ||
): Promise<Deployment> { | ||
const deployment = fn({ version }); | ||
if (!deployment) { | ||
throw new Error(`Deployment not found for ${fn.name} version ${version}`); | ||
} | ||
// TODO: maybe call parseAbi on deployment.abi here. | ||
return { | ||
address: deployment.networkAddresses["11155111"] as Address, | ||
abi: deployment.abi, | ||
}; | ||
} | ||
|
||
export async function fetchDeployments( | ||
safeVersion: string = SAFE_VERSION, | ||
moduleVersion: string = MODULE_VERSION | ||
): Promise<SafeDeployments> { | ||
console.log("Fetching deployments..."); | ||
const safeDeployment = async (fn: DeploymentFn): Promise<Deployment> => | ||
getDeployment(fn, { version: safeVersion }); | ||
|
||
const m4337Deployment = async (fn: DeploymentFn): Promise<Deployment> => | ||
getDeployment(fn, { version: moduleVersion }); | ||
|
||
try { | ||
// Fetch deployments for Safe and 4337 modules | ||
const [singleton, proxyFactory, moduleSetup, m4337] = await Promise.all([ | ||
safeDeployment(getSafeL2SingletonDeployment), | ||
safeDeployment(getProxyFactoryDeployment), | ||
m4337Deployment(getSafeModuleSetupDeployment), | ||
m4337Deployment(getSafe4337ModuleDeployment), | ||
]); | ||
// TODO - this is a cheeky hack. | ||
const client = getClient(11155111); | ||
const entryPoint = { | ||
address: (await client.readContract({ | ||
address: m4337.address, | ||
abi: m4337.abi, | ||
functionName: "SUPPORTED_ENTRYPOINT", | ||
})) as Address, | ||
abi: parseAbi([ | ||
"function getNonce(address, uint192 key) view returns (uint256 nonce)", | ||
]), | ||
}; | ||
return { | ||
singleton, | ||
proxyFactory, | ||
moduleSetup, | ||
m4337, | ||
entryPoint, | ||
}; | ||
} catch (error) { | ||
throw new Error(`Error fetching deployments: ${error}`); | ||
} | ||
} |
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,78 @@ | ||
import fs from "fs"; | ||
import path from "path"; | ||
|
||
import { | ||
fetchDeployments, | ||
MODULE_VERSION, | ||
SAFE_VERSION, | ||
} from "./fetch-deployments"; | ||
|
||
// Main function to fetch and write deployment data | ||
export async function fetchAndWriteDeployments( | ||
outPath: string = "src/_gen", | ||
safeVersion: string = SAFE_VERSION, | ||
moduleVersion: string = MODULE_VERSION | ||
): Promise<void> { | ||
const { singleton, proxyFactory, moduleSetup, m4337, entryPoint } = | ||
await fetchDeployments(safeVersion, moduleVersion); | ||
|
||
try { | ||
// Specify output file path | ||
const outputPath = path.join(process.cwd(), outPath, "deployments.ts"); | ||
// const outputPath = path.join( | ||
// process.cwd(), | ||
// outPath, | ||
// `safe_v${safeVersion}_module_v${moduleVersion}.json` | ||
// ); | ||
|
||
// Ensure the directory exists | ||
if (!fs.existsSync(path.dirname(outputPath))) { | ||
fs.mkdirSync(path.dirname(outputPath), { recursive: true }); | ||
} | ||
|
||
// Write deployment data to file | ||
// fs.writeFileSync(outputPath, JSON.stringify(deployments, null, 2)); | ||
const tsContent = ` | ||
// Auto-generated file from build script | ||
import { SafeDeployments } from "../types"; | ||
export const SAFE_DEPLOYMENTS: SafeDeployments = { | ||
singleton: { | ||
address: "${singleton.address}", | ||
abi: ${JSON.stringify(singleton.abi, null, 2)}, | ||
}, | ||
proxyFactory: { | ||
address: "${proxyFactory.address}", | ||
abi: ${JSON.stringify(proxyFactory.abi, null, 2)}, | ||
}, | ||
moduleSetup: { | ||
address: "${moduleSetup.address}", | ||
abi: ${JSON.stringify(moduleSetup.abi, null, 2)}, | ||
}, | ||
m4337: { | ||
address: "${m4337.address}", | ||
abi: ${JSON.stringify(m4337.abi, null, 2)}, | ||
}, | ||
entryPoint: { | ||
address: "${entryPoint.address}", | ||
abi: ${JSON.stringify(entryPoint.abi, null, 2)}, | ||
}, | ||
}; | ||
`; | ||
fs.writeFileSync(outputPath, tsContent, "utf-8"); | ||
console.log( | ||
`TypeScript constants generated at ${path.join(outPath, "deployments.ts")}` | ||
); | ||
} catch (error) { | ||
console.error("Error fetching deployments:", error); | ||
} | ||
} | ||
|
||
async function main(): Promise<void> { | ||
await fetchAndWriteDeployments(); | ||
} | ||
|
||
main().catch((err) => { | ||
console.error(err); | ||
process.exitCode = 1; | ||
}); |
Oops, something went wrong.