diff --git a/arbitrum-one.ts b/arbitrum-one.ts new file mode 100644 index 0000000..f3e3052 --- /dev/null +++ b/arbitrum-one.ts @@ -0,0 +1,39 @@ +import { NitroRollup } from '@unruggable/gateways'; +import { createProviderPair, providerURL } from './providers'; +import { runExample } from './example-base'; +import { type ConfigItem } from './utils'; + +const config = NitroRollup.arb1MainnetConfig; + +// Make sure you've created a .env and added node provider API keys +console.log(providerURL(config.chain1)); +console.log(providerURL(config.chain2)); + +const provider = providerURL(config.chain1); +const rollup = await new NitroRollup( + createProviderPair(config), + config +); +const verifierPath = `@unruggable/contracts/nitro/NitroVerifier.sol`; +const verifierArgs: any[] = []; +const GATEWAY_URL = 'https://arbitrum-one.gateway.unruggable.com'; +//This is the address of the SlotDataContract deployed on the L2 (that we fork) +const EXAMPLE_CONTRACT_ADDRESS = '0xCC344B12fcc8512cc5639CeD6556064a8907c8a1'; //Arb +const configurationToSet: ConfigItem[] = [ + { + getter: 'getWindow', + setter: 'setWindow', + value: rollup.defaultWindow, + }, + { + getter: 'gatewayURLs', + setter: 'setGatewayURLs', + value: [GATEWAY_URL], + }, + { + setter: 'setRollup', + value: rollup.L2Rollup.target, + }, +]; + +runExample(provider, verifierPath, verifierArgs, configurationToSet, EXAMPLE_CONTRACT_ADDRESS); \ No newline at end of file diff --git a/arbitrum.ts b/arbitrum.ts deleted file mode 100644 index 5c04d1f..0000000 --- a/arbitrum.ts +++ /dev/null @@ -1,113 +0,0 @@ -import { Foundry } from '@adraffy/blocksmith'; -import { NitroRollup, Gateway, solidityFollowSlot } from '@unruggable/gateways'; -import { ethers } from 'ethers'; -import { createProviderPair, providerURL } from './providers'; - - -const NAME_TO_TEST = "unruggable.eth"; - -const config = NitroRollup.arb1MainnetConfig; - -// Make sure you've created a .env and added node provider API keys -console.log(providerURL(config.chain1)); -console.log(providerURL(config.chain2)); -//process.exit(); - -const rollup = await new NitroRollup(createProviderPair(config), - config); -const gateway = new Gateway(rollup); -const commit = await gateway.getLatestCommit(); - -//const gateway = new Gateway(rollup); -//const ccip = await serve(gateway, { protocol: 'raw' }); - -const GATEWAY_URL = 'https://arb-gateway.unruggable.com'; - -const foundry = await Foundry.launch({ - fork: providerURL(config.chain1), - procLog : true, - infoLog : true, -}); - -const deployerWallet = foundry.wallets.admin; - -//Deploy verifier -const verifier = await foundry.deploy({ - import: `@unruggable/contracts/nitro/NitroVerifier.sol`, - args: [], -}); - -//Deploy proxy -const proxy = await foundry.deploy({ - import: `@unruggable/lib/openzeppelin-contracts/contracts/proxy/transparent/TransparentUpgradeableProxy.sol`, - args: [verifier.target, deployerWallet.address, '0x'], -}); - -// Instantiate the proxy using the undelrlying verifier interface -const proxyUsingInterface = new ethers.Contract( - proxy.target, - verifier.interface, - deployerWallet -); - -// Configure the verifier -await foundry.confirm( - proxyUsingInterface.setGatewayURLs([GATEWAY_URL]) -); -await foundry.confirm(proxyUsingInterface.setWindow(rollup.defaultWindow)); -await foundry.confirm(proxyUsingInterface.setRollup(rollup.L2Rollup.target)); - -const ENS = '0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e'; -const NODE = ethers.namehash(NAME_TO_TEST); -const SLOT = solidityFollowSlot(0, NODE) + 1n; - -//This is the address of the SlotDataContract deployed on the L2 (that we fork) -const EXAMPLE_CONTRACT_ADDRESS = '0xCC344B12fcc8512cc5639CeD6556064a8907c8a1'; //Arb - -// Test with the ExampleResolver that reads a value from our live deployed SlotDataContract -// Uncomment this block, and comment the block below to test with the ExampleResolver - const opL1Resolver = await foundry.deploy({ - file: 'ExampleResolver', - args: [proxy.target, EXAMPLE_CONTRACT_ADDRESS], - }); - -// Test with the OPResolver that reads does a complex v2-spec like resolution -/*const opL1Resolver = await foundry.deploy({ - file: 'OPResolver', - args: [proxy.target], -});*/ - - -console.log('Resolver depl:', opL1Resolver.target); - -// replace real teamnick resolver with fake -await foundry.provider.send('anvil_setStorageAt', [ - ENS, - ethers.toBeHex(SLOT, 32), - ethers.toBeHex(opL1Resolver.target, 32), -]); -const ens = new ethers.Contract( - ENS, - ['function resolver(bytes32 node) view returns (address)'], - foundry.provider -); -console.log('Hijacked:', await ens.resolver(NODE)); - -async function resolve(name: string, keys = ['avatar'], coinType = 60) { - const resolver = await foundry.provider.getResolver(name); - - console.log("Resolver", resolver); - - if (!resolver) throw new Error('bug'); - const [address] = await Promise.all([ - resolver.getAddress(coinType) - ]); - console.log({ - name, - address, - }); -} - -await resolve(NAME_TO_TEST); - -await foundry.shutdown(); \ No newline at end of file diff --git a/bun.lockb b/bun.lockb index 119285b..1e72dbe 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/example-base.ts b/example-base.ts new file mode 100644 index 0000000..d4741d7 --- /dev/null +++ b/example-base.ts @@ -0,0 +1,92 @@ +import { Foundry } from '@adraffy/blocksmith'; +import { namehash, toBeHex, Contract } from 'ethers'; +import { type ConfigItem, type VerifierArgsType } from './utils'; +import { solidityFollowSlot } from '@unruggable/gateways'; + +const NAME_TO_TEST = "unruggable.eth"; + +export const runExample = async ( + chainLink: string, + verifierPath: string, + verifierArgs: VerifierArgsType, + configurationToSet: ConfigItem[], + exampleContractAddress: string +) => { + + const foundry = await Foundry.launch({ + fork: chainLink, + procLog : true, + infoLog : true, + }); + + const deployerWallet = foundry.wallets.admin; + + const verifierArgsToUse = typeof verifierArgs === 'function' ? await verifierArgs(foundry) : verifierArgs; + + //Deploy verifier + const verifier = await foundry.deploy({ + import: verifierPath, + args: verifierArgsToUse, + }); + + //Deploy proxy + const proxy = await foundry.deploy({ + import: `@unruggable/lib/openzeppelin-contracts/contracts/proxy/transparent/TransparentUpgradeableProxy.sol`, + args: [verifier.target, deployerWallet.address, '0x'], + }); + + // Instantiate the proxy using the underlying verifier interface + const proxyUsingInterface = new Contract( + proxy.target, + verifier.interface, + deployerWallet + ); + + // Configure the verifier + for (const config of configurationToSet) { + await foundry.confirm(proxyUsingInterface[config.setter](config.value)); + console.log(`Set ${config.setter} to ${config.value}`); + } + + const ENS = '0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e'; + const NODE = namehash(NAME_TO_TEST); + const SLOT = solidityFollowSlot(0, NODE) + 1n; + + const arbitrumOneResolver = await foundry.deploy({ + file: 'ExampleResolver', + args: [proxy.target, exampleContractAddress], + }); + + console.log('Arbitrum One Resolver deployment:', arbitrumOneResolver.target); + + await foundry.provider.send('anvil_setStorageAt', [ + ENS, + toBeHex(SLOT, 32), + toBeHex(arbitrumOneResolver.target, 32), + ]); + const ens = new Contract( + ENS, + ['function resolver(bytes32 node) view returns (address)'], + foundry.provider + ); + console.log('Hijacked:', await ens.resolver(NODE)); + + async function resolve(name: string, keys = ['avatar'], coinType = 60) { + const resolver = await foundry.provider.getResolver(name); + + console.log("Resolver", resolver); + + if (!resolver) throw new Error('bug'); + const [address] = await Promise.all([ + resolver.getAddress(coinType) + ]); + console.log({ + name, + address, + }); + } + + await resolve(NAME_TO_TEST); + + await foundry.shutdown(); +} diff --git a/optimism.ts b/optimism.ts index 25326c9..26d90c4 100644 --- a/optimism.ts +++ b/optimism.ts @@ -1,136 +1,70 @@ import { Foundry } from '@adraffy/blocksmith'; -import { OPFaultRollup, Gateway, solidityFollowSlot } from '@unruggable/gateways'; -import { ethers } from 'ethers'; +import { OPFaultRollup, Gateway } from '@unruggable/gateways'; import { createProviderPair, providerURL } from './providers'; - - -const NAME_TO_TEST = "unruggable.eth"; +import type { ConfigItem, VerifierArgsType } from './utils'; +import { runExample } from './example-base'; const config = OPFaultRollup.mainnetConfig; // Make sure you've created a .env and added node provider API keys -// console.log(providerURL(config.chain1)); +console.log(providerURL(config.chain1)); +console.log(providerURL(config.chain2)); +const provider = providerURL(config.chain1); const rollup = await OPFaultRollup.create( createProviderPair(config), config ); + const gateway = new Gateway(rollup); const commit = await gateway.getLatestCommit(); -//const gateway = new Gateway(rollup); -//const ccip = await serve(gateway, { protocol: 'raw' }); - -const GATEWAY_URL = 'https://op-gateway.unruggable.com'; - -const foundry = await Foundry.launch({ - fork: providerURL(config.chain1), - procLog : true, - infoLog : true, -}); - -const deployerWallet = foundry.wallets.admin; - -//const gameFinderName = 'FixedOPFaultGameFinder'; -//let gameFinderArgs = [Number(commit.index)]; +const verifierPath = `@unruggable/contracts/op/OPFaultVerifier.sol`; +const GATEWAY_URL = 'https://optimism.gateway.unruggable.com'; -//Deploy gamefinder -/* -// When working with the real gamefinder in the anvil context, iteration is slow. -// ~80s noting the latest fixes to OP fault proving (see https://gov.optimism.io/t/upgrade-proposal-10-granite-network-upgrade/8733) -// We use a fixed gamefinder for demonstration purposes. -// Swap in the below block to use the real gamefinder. -const gameFinder = await foundry.deploy({ - import: `@unruggable/contracts/op/OPFaultGameFinder.sol`, - args: [], -}); -*/ - -const gameFinder = await foundry.deploy({ - import: `@unruggable/test/gateway/FixedOPFaultGameFinder.sol`, - args: [commit.index], -}); - - -//Deploy verifier -const verifier = await foundry.deploy({ - import: `@unruggable/contracts/op/OPFaultVerifier.sol`, - args: [gameFinder.target], -}); - -//Deploy proxy -const proxy = await foundry.deploy({ - import: `@unruggable/lib/openzeppelin-contracts/contracts/proxy/transparent/TransparentUpgradeableProxy.sol`, - args: [verifier.target, deployerWallet.address, '0x'], -}); - -// Instantiate the proxy using the undelrlying verifier interface -const proxyUsingInterface = new ethers.Contract( - proxy.target, - verifier.interface, - deployerWallet -); - -// Configure the verifier -await foundry.confirm( - proxyUsingInterface.setGatewayURLs([GATEWAY_URL]) -); -await foundry.confirm(proxyUsingInterface.setWindow(rollup.defaultWindow)); -await foundry.confirm(proxyUsingInterface.setPortal(rollup.OptimismPortal.target)); -await foundry.confirm(proxyUsingInterface.setGameTypes(rollup.gameTypeBitMask)); +const verifierArgs: VerifierArgsType = async (foundry) => { -const ENS = '0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e'; -const NODE = ethers.namehash(NAME_TO_TEST); -const SLOT = solidityFollowSlot(0, NODE) + 1n; - -//This is the address of the SlotDataContract deployed on the L2 (that we fork) -const EXAMPLE_CONTRACT_ADDRESS = '0xf9d79d8c09d24e0C47E32778c830C545e78512CF'; - -// Test with the ExampleResolver that reads a value from our live deployed SlotDataContract -// Uncomment this block, and comment the block below to test with the ExampleResolver - const opL1Resolver = await foundry.deploy({ - file: 'ExampleResolver', - args: [proxy.target, EXAMPLE_CONTRACT_ADDRESS], - }); - -// Test with the OPResolver that reads does a complex v2-spec like resolution -/*const opL1Resolver = await foundry.deploy({ - file: 'OPResolver', - args: [proxy.target], -});*/ - - -console.log('Resolver depl:', opL1Resolver.target); - -// replace real teamnick resolver with fake -await foundry.provider.send('anvil_setStorageAt', [ - ENS, - ethers.toBeHex(SLOT, 32), - ethers.toBeHex(opL1Resolver.target, 32), -]); -const ens = new ethers.Contract( - ENS, - ['function resolver(bytes32 node) view returns (address)'], - foundry.provider -); -console.log('Hijacked:', await ens.resolver(NODE)); - -async function resolve(name: string, keys = ['avatar'], coinType = 60) { - const resolver = await foundry.provider.getResolver(name); - - console.log("Resolver", resolver); + //Deploy gamefinder + /* + // When working with the real gamefinder in the anvil context, iteration is slow. + // ~80s noting the latest fixes to OP fault proving (see https://gov.optimism.io/t/upgrade-proposal-10-granite-network-upgrade/8733) + // We use a fixed gamefinder for demonstration purposes. + // Swap in the below block to use the real gamefinder. + const gameFinder = await foundry.deploy({ + import: `@unruggable/contracts/op/OPFaultGameFinder.sol`, + args: [], + }); + */ - if (!resolver) throw new Error('bug'); - const [address] = await Promise.all([ - resolver.getAddress(coinType) - ]); - console.log({ - name, - address, + const gameFinder = await foundry.deploy({ + import: `@unruggable/test/gateway/FixedOPFaultGameFinder.sol`, + args: [commit.index], }); -} -await resolve(NAME_TO_TEST); + return [gameFinder.target]; +} -await foundry.shutdown(); \ No newline at end of file +const EXAMPLE_CONTRACT_ADDRESS = '0xf9d79d8c09d24e0C47E32778c830C545e78512CF'; +const configurationToSet: ConfigItem[] = [ + { + getter: 'getWindow', + setter: 'setWindow', + value: rollup.defaultWindow, + }, + { + getter: 'gatewayURLs', + setter: 'setGatewayURLs', + value: [GATEWAY_URL], + }, + { + setter: 'setPortal', + value: rollup.OptimismPortal.target, + }, + { + setter: 'setGameTypes', + value: rollup.gameTypeBitMask, + }, +]; + +runExample(provider, verifierPath, verifierArgs, configurationToSet, EXAMPLE_CONTRACT_ADDRESS); \ No newline at end of file diff --git a/utils.ts b/utils.ts new file mode 100644 index 0000000..bf11f9c --- /dev/null +++ b/utils.ts @@ -0,0 +1,9 @@ +import { Wallet } from 'ethers'; + +export type ConfigItem = { + getter?: string; + setter: string; + value: any; +}; + +export type VerifierArgsType = any[] | ((smith: any) => Promise);