@@ -8,20 +8,34 @@ import chalk from "chalk";
88import { ExecaError } from "execa" ;
99import getPort , { portNumbers } from "get-port" ;
1010import ora from "ora" ;
11- import { type Address , type Hex , numberToHex } from "viem" ;
11+ import {
12+ type Address ,
13+ createPublicClient ,
14+ type Hex ,
15+ http ,
16+ numberToHex ,
17+ } from "viem" ;
1218import { getMachineHash , getProjectName } from "../base.js" ;
1319import { DEFAULT_SDK_VERSION , PREFERRED_PORT } from "../config.js" ;
1420import {
1521 AVAILABLE_SERVICES ,
16- type RollupsDeployment ,
1722 deployApplication ,
1823 removeApplication ,
24+ type RollupsDeployment ,
1925 startEnvironment ,
2026 stopEnvironment ,
2127 waitHealthyEnvironment ,
2228} from "../exec/rollups.js" ;
2329import { keySelect } from "../prompts.js" ;
2430
31+ const DEFAULT_FORK_URL = "https://ethereum.reth.rs/rpc" ;
32+
33+ export type ForkConfig = {
34+ blockNumber ?: bigint ;
35+ chainId : number ;
36+ url : string ;
37+ } ;
38+
2539const commaSeparatedList = ( value : string ) => value . split ( "," ) ;
2640
2741const shell = async ( options : {
@@ -165,6 +179,37 @@ const deploy = async (options: {
165179 return application ;
166180} ;
167181
182+ const configureFork = async ( options : {
183+ fork ?: true | undefined ;
184+ forkUrl ?: string ;
185+ forkBlockNumber ?: number ;
186+ } ) : Promise < ForkConfig | undefined > => {
187+ // determine fork mode: explicit --fork flag or --fork-url provided
188+ const isFork = options . fork || options . forkUrl !== undefined ;
189+
190+ if ( ! isFork ) {
191+ return undefined ;
192+ }
193+
194+ // assign default fork url
195+ const url = options . forkUrl ?? DEFAULT_FORK_URL ;
196+
197+ // create a client to upstream so we can query it
198+ const client = createPublicClient ( {
199+ transport : http ( url ) ,
200+ } ) ;
201+
202+ // use explicit fork-block-number or query from upstream
203+ const blockNumber = options . forkBlockNumber
204+ ? BigInt ( options . forkBlockNumber )
205+ : await client . getBlockNumber ( ) ;
206+
207+ // need to query fork chainId if forkUrl is specified
208+ const chainId = await client . getChainId ( ) ;
209+
210+ return { blockNumber, chainId, url } ;
211+ } ;
212+
168213export const createRunCommand = ( ) => {
169214 return new Command ( "run" )
170215 . description ( "Run a local cartesi node for the application." )
@@ -197,6 +242,17 @@ export const createRunCommand = () => {
197242 . default ( "latest" ) ,
198243 )
199244 . option ( "--dry-run" , "show the docker compose configuration" , false )
245+ . option (
246+ "--fork" ,
247+ "fork from a live chain instead of using devnet state" ,
248+ )
249+ . option ( "--fork-url <url>" , "RPC URL to fork from (implies --fork)" )
250+ . addOption (
251+ new Option (
252+ "--fork-block-number <number>" ,
253+ "block number to fork from" ,
254+ ) . argParser ( Number ) ,
255+ )
200256 . addOption (
201257 new Option (
202258 "--memory <number>" ,
@@ -265,12 +321,16 @@ export const createRunCommand = () => {
265321 port : portNumbers ( PREFERRED_PORT , PREFERRED_PORT + 10 ) ,
266322 } ) ) ;
267323
324+ // configure optional anvil fork
325+ const forkConfig = await configureFork ( options ) ;
326+
268327 // run compose environment (detached)
269328 const { address, config } = await startEnvironment ( {
270329 blockTime,
271330 cpus,
272331 defaultBlock,
273332 dryRun,
333+ forkConfig,
274334 memory,
275335 port,
276336 projectName,
0 commit comments