|
| 1 | +const fs = require('fs'); |
| 2 | +const path = require('path'); |
| 3 | +const Web3 = require('web3'); |
| 4 | +const { gray, red } = require('chalk'); |
| 5 | +const { wrap, toBytes32 } = require('../../..'); |
| 6 | +const { |
| 7 | + ensureNetwork, |
| 8 | + ensureDeploymentPath, |
| 9 | + getDeploymentPathForNetwork, |
| 10 | + loadConnections, |
| 11 | +} = require('../util'); |
| 12 | + |
| 13 | +const connectBridge = async ({ |
| 14 | + l1Network, |
| 15 | + l2Network, |
| 16 | + l1DeploymentPath, |
| 17 | + l2DeploymentPath, |
| 18 | + l1PrivateKey, |
| 19 | + l2PrivateKey, |
| 20 | + l1UseFork, |
| 21 | + l2UseFork, |
| 22 | + l1Messenger, |
| 23 | + l2Messenger, |
| 24 | +}) => { |
| 25 | + console.log(gray('> Connecting with L1 instance...')); |
| 26 | + const { |
| 27 | + AddressResolver: AddressResolverL1, |
| 28 | + SynthetixBridge: SynthetixBridgeToOptimism, |
| 29 | + } = await connectInstance({ |
| 30 | + network: l1Network, |
| 31 | + deploymentPath: l1DeploymentPath, |
| 32 | + privateKey: l1PrivateKey, |
| 33 | + useFork: l1UseFork, |
| 34 | + messenger: l1Messenger, |
| 35 | + useOvm: false, |
| 36 | + }); |
| 37 | + |
| 38 | + console.log(gray('> Connecting with L2 instance...')); |
| 39 | + const { |
| 40 | + AddressResolver: AddressResolverL2, |
| 41 | + SynthetixBridge: SynthetixBridgeToBase, |
| 42 | + } = await connectInstance({ |
| 43 | + network: l2Network, |
| 44 | + deploymentPath: l2DeploymentPath, |
| 45 | + privateKey: l2PrivateKey, |
| 46 | + useFork: l2UseFork, |
| 47 | + messenger: l2Messenger, |
| 48 | + useOvm: true, |
| 49 | + }); |
| 50 | + |
| 51 | + console.log(gray('> Connecting bridge on L1...')); |
| 52 | + await AddressResolverL1.importAddresses( |
| 53 | + [toBytes32('ext:Messenger'), toBytes32('ovm:SynthetixBridgeToBase')], |
| 54 | + l1Messenger, |
| 55 | + SynthetixBridgeToBase.options.address |
| 56 | + ); |
| 57 | + await SynthetixBridgeToBase.setResolverAndSyncCache(AddressResolverL1.options.address); |
| 58 | + |
| 59 | + console.log(gray('> Connecting bridge on L2...')); |
| 60 | + await AddressResolverL2.importAddresses( |
| 61 | + [toBytes32('ext:Messenger'), toBytes32('base:SynthetixBridgeToOptimism')], |
| 62 | + l2Messenger, |
| 63 | + SynthetixBridgeToOptimism.options.address |
| 64 | + ); |
| 65 | + await SynthetixBridgeToOptimism.setResolverAndSyncCache(AddressResolverL2.options.address); |
| 66 | +}; |
| 67 | + |
| 68 | +const connectInstance = async ({ network, deploymentPath, privateKey, useFork, useOvm }) => { |
| 69 | + console.log(gray(' > network:', network)); |
| 70 | + console.log(gray(' > deploymentPath:', deploymentPath)); |
| 71 | + console.log(gray(' > privateKey:', privateKey)); |
| 72 | + console.log(gray(' > useFork:', useFork)); |
| 73 | + console.log(gray(' > useOvm:', useOvm)); |
| 74 | + |
| 75 | + const { web3, getSource, getTarget } = bootstrapConnection({ |
| 76 | + network, |
| 77 | + deploymentPath, |
| 78 | + privateKey, |
| 79 | + useFork, |
| 80 | + useOvm, |
| 81 | + }); |
| 82 | + |
| 83 | + const AddressResolver = getContract({ |
| 84 | + contract: 'AddressResolver', |
| 85 | + getTarget, |
| 86 | + getSource, |
| 87 | + deploymentPath, |
| 88 | + web3, |
| 89 | + }); |
| 90 | + console.log(gray(' > AddressResolver:', AddressResolver.options.address)); |
| 91 | + |
| 92 | + const bridgeName = useOvm ? 'SynthetixBridgeToBase' : 'SynthetixBridgeToOptimism'; |
| 93 | + const SynthetixBridge = getContract({ |
| 94 | + contract: bridgeName, |
| 95 | + getTarget, |
| 96 | + getSource, |
| 97 | + deploymentPath, |
| 98 | + web3, |
| 99 | + }); |
| 100 | + console.log(gray(` > ${bridgeName}:`, SynthetixBridge.options.address)); |
| 101 | + |
| 102 | + return { |
| 103 | + AddressResolver, |
| 104 | + SynthetixBridge, |
| 105 | + }; |
| 106 | +}; |
| 107 | + |
| 108 | +const bootstrapConnection = ({ network, deploymentPath, privateKey, useFork, useOvm }) => { |
| 109 | + ensureNetwork(network); |
| 110 | + deploymentPath = deploymentPath || getDeploymentPathForNetwork({ network, useOvm }); |
| 111 | + ensureDeploymentPath(deploymentPath); |
| 112 | + |
| 113 | + const { providerUrl, privateKey: envPrivateKey } = loadConnections({ |
| 114 | + network, |
| 115 | + useFork, |
| 116 | + }); |
| 117 | + |
| 118 | + // allow local deployments to use the private key passed as a CLI option |
| 119 | + if (network !== 'local' || !privateKey) { |
| 120 | + privateKey = envPrivateKey; |
| 121 | + } |
| 122 | + |
| 123 | + const web3 = new Web3(new Web3.providers.HttpProvider(providerUrl)); |
| 124 | + |
| 125 | + const { getUsers, getTarget, getSource } = wrap({ network, useOvm, fs, path }); |
| 126 | + |
| 127 | + let account; |
| 128 | + if (useFork) { |
| 129 | + account = getUsers({ network, user: 'owner' }).address; // protocolDAO |
| 130 | + } else { |
| 131 | + web3.eth.accounts.wallet.add(privateKey); |
| 132 | + account = web3.eth.accounts.wallet[0].address; |
| 133 | + } |
| 134 | + |
| 135 | + return { |
| 136 | + deploymentPath, |
| 137 | + privateKey, |
| 138 | + web3, |
| 139 | + account, |
| 140 | + getTarget, |
| 141 | + getSource, |
| 142 | + getUsers, |
| 143 | + }; |
| 144 | +}; |
| 145 | + |
| 146 | +const getContract = ({ contract, deploymentPath, getTarget, getSource, web3 }) => { |
| 147 | + const target = getTarget({ deploymentPath, contract }); |
| 148 | + if (!target) { |
| 149 | + throw new Error(`Unable to find deployed target for ${contract} in ${deploymentPath}`); |
| 150 | + } |
| 151 | + |
| 152 | + const source = getSource({ deploymentPath, contract }); |
| 153 | + if (!source) { |
| 154 | + throw new Error(`Unable to find source for ${contract}`); |
| 155 | + } |
| 156 | + |
| 157 | + return new web3.eth.Contract(source.abi, target.address); |
| 158 | +}; |
| 159 | + |
| 160 | +module.exports = { |
| 161 | + connectBridge, |
| 162 | + cmd: program => |
| 163 | + program |
| 164 | + .command('connect-bridge') |
| 165 | + .description('Configures the bridge between an L1-L2 instance pair.') |
| 166 | + .option('--l1-network <value>', 'The name of the target L1 network', 'goerli') |
| 167 | + .option('--l2-network <value>', 'The name of the target L2 network', 'goerli') |
| 168 | + .option('--l1-deployment-path <value>', 'The path of the L1 deployment to target') |
| 169 | + .option('--l2-deployment-path <value>', 'The path of the L2 deployment to target') |
| 170 | + .option('--l1-private-key <value>', 'Optional private key for signing L1 transactions') |
| 171 | + .option('--l2-private-key <value>', 'Optional private key for signing L2 transactions') |
| 172 | + .option('--l1-use-fork', 'Wether to use a fork for the L1 connection', false) |
| 173 | + .option('--l2-use-fork', 'Wether to use a fork for the L2 connection', false) |
| 174 | + .option('--l1-messenger <value>', 'L1 cross domain messenger to use') |
| 175 | + .option('--l2-messenger <value>', 'L2 cross domain messenger to use') |
| 176 | + .action(async (...args) => { |
| 177 | + try { |
| 178 | + await connectBridge(...args); |
| 179 | + } catch (err) { |
| 180 | + console.error(red(err)); |
| 181 | + console.log(err.stack); |
| 182 | + process.exitCode = 1; |
| 183 | + } |
| 184 | + }), |
| 185 | +}; |
0 commit comments