github.com/ethereum-optimism/optimism@v1.7.2/packages/core-utils/src/helpers/setupProxyContract.ts (about) 1 import assert from 'assert' 2 3 import { ethers, utils } from 'ethers' 4 5 const { getAddress } = utils 6 7 type ProxyConfig = { 8 targetImplAddress: string 9 targetProxyOwnerAddress: string 10 postUpgradeCallCalldata?: string 11 } 12 13 // Sets up the newly deployed proxy contract such that: 14 // 1. The proxy's implementation is set to the target implementation 15 // 2. The proxy's admin is set to the target proxy owner 16 // 17 // If the values are set correctly already, it makes no transactions. 18 19 const setupProxyContract = async ( 20 proxyContract: ethers.Contract, 21 signer: ethers.Signer, 22 { 23 targetImplAddress, 24 targetProxyOwnerAddress, 25 postUpgradeCallCalldata, 26 }: ProxyConfig 27 ) => { 28 const currentAdmin = await proxyContract 29 .connect(ethers.constants.AddressZero) 30 .callStatic.admin() 31 32 const signerAddress = await signer.getAddress() 33 34 // Gets the current implementation address the proxy is pointing to. 35 // callStatic is used since the `Proxy.implementation()` is not a view function and ethers will 36 // try to make a transaction if we don't use callStatic. Using the zero address as `from` lets us 37 // call functions on the proxy and not trigger the delegatecall. See Proxy.sol proxyCallIfNotAdmin 38 // modifier for more details. 39 const currentImplementation = await proxyContract 40 .connect(ethers.constants.AddressZero) 41 .callStatic.implementation() 42 console.log(`implementation currently set to ${currentImplementation}`) 43 44 if (getAddress(currentImplementation) !== getAddress(targetImplAddress)) { 45 // If the proxy isn't pointing to the correct implementation, we need to set it to the correct 46 // one, then call initialize() in the proxy's context. 47 48 console.log('implementation not set to correct contract') 49 console.log(`Setting implementation to ${targetImplAddress}`) 50 51 // The signer needs to be the current admin, otherwise we don't have permission 52 // to update the implementation or admin 53 assert( 54 signerAddress === currentAdmin, 55 'the passed signer is not the admin, cannot update implementation' 56 ) 57 58 let tx: ethers.providers.TransactionResponse 59 if (!postUpgradeCallCalldata) { 60 console.log( 61 'postUpgradeCallCalldata is not provided. Using Proxy.upgrade()' 62 ) 63 // Point the proxy to the target implementation 64 tx = await proxyContract.connect(signer).upgradeTo(targetImplAddress) 65 } else { 66 console.log( 67 'postUpgradeCallCalldata is provided. Using Proxy.upgradeAndCall()' 68 ) 69 // Point the proxy to the target implementation, 70 // and call function in the proxy's context 71 tx = await proxyContract 72 .connect(signer) 73 .upgradeToAndCall(targetImplAddress, postUpgradeCallCalldata) 74 } 75 76 const receipt = await tx.wait() 77 78 console.log(`implementation set in ${receipt.transactionHash}`) 79 } else { 80 console.log(`implementation already set correctly to ${targetImplAddress}`) 81 } 82 83 console.log(`admin set to ${currentAdmin}`) 84 if (getAddress(currentAdmin) !== getAddress(targetProxyOwnerAddress)) { 85 // If the proxy admin isn't the l2ProxyOwnerAddress, we need to update it 86 // We're assuming that the proxy admin is the ddd right now. 87 88 console.log('detected admin is not set correctly') 89 console.log(`Setting admin to ${targetProxyOwnerAddress}`) 90 91 // The signer needs to be the current admin, otherwise we don't have permission 92 // to update the implementation or admin 93 assert( 94 signerAddress === currentAdmin, 95 'proxyOwnerSigner is not the admin, cannot update admin' 96 ) 97 98 // change admin to the l2ProxyOwnerAddress 99 const tx = await proxyContract 100 .connect(signer) 101 .changeAdmin(targetProxyOwnerAddress) 102 103 const receipt = await tx.wait() 104 105 console.log(`admin set in ${receipt.transactionHash}`) 106 } else { 107 console.log(`admin already set correctly to ${targetProxyOwnerAddress}`) 108 } 109 110 const updatedImplementation = await proxyContract 111 .connect(ethers.constants.AddressZero) 112 .callStatic.implementation() 113 114 const updatedAdmin = await proxyContract 115 .connect(ethers.constants.AddressZero) 116 .callStatic.admin() 117 118 assert( 119 getAddress(updatedAdmin) === getAddress(targetProxyOwnerAddress), 120 'Something went wrong - admin not set correctly after transaction' 121 ) 122 assert( 123 getAddress(updatedImplementation) === getAddress(targetImplAddress), 124 'Something went wrong - implementation not set correctly after transaction' 125 ) 126 127 console.log( 128 `Proxy at ${proxyContract.address} is set up with implementation: ${updatedImplementation} and admin: ${updatedAdmin}` 129 ) 130 } 131 132 export { setupProxyContract }