setupProxyContract.ts 4.54 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
import assert from 'assert'

import { ethers, utils } from 'ethers'

const { getAddress } = utils

type ProxyConfig = {
  targetImplAddress: string
  targetProxyOwnerAddress: string
  postUpgradeCallCalldata?: string
}

// Sets up the newly deployed proxy contract such that:
// 1. The proxy's implementation is set to the target implementation
// 2. The proxy's admin is set to the target proxy owner
//
// If the values are set correctly already, it makes no transactions.

const setupProxyContract = async (
  proxyContract: ethers.Contract,
21
  signer: ethers.Signer,
22 23 24 25 26 27 28 29 30 31
  {
    targetImplAddress,
    targetProxyOwnerAddress,
    postUpgradeCallCalldata,
  }: ProxyConfig
) => {
  const currentAdmin = await proxyContract
    .connect(ethers.constants.AddressZero)
    .callStatic.admin()

32
  const signerAddress = await signer.getAddress()
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50

  // Gets the current implementation address the proxy is pointing to.
  // callStatic is used since the `Proxy.implementation()` is not a view function and ethers will
  // try to make a transaction if we don't use callStatic. Using the zero address as `from` lets us
  // call functions on the proxy and not trigger the delegatecall. See Proxy.sol proxyCallIfNotAdmin
  // modifier for more details.
  const currentImplementation = await proxyContract
    .connect(ethers.constants.AddressZero)
    .callStatic.implementation()
  console.log(`implementation currently set to ${currentImplementation}`)

  if (getAddress(currentImplementation) !== getAddress(targetImplAddress)) {
    // If the proxy isn't pointing to the correct implementation, we need to set it to the correct
    // one, then call initialize() in the proxy's context.

    console.log('implementation not set to correct contract')
    console.log(`Setting implementation to ${targetImplAddress}`)

51 52 53 54 55 56 57
    // The signer needs to be the current admin, otherwise we don't have permission
    // to update the implmentation or admin
    assert(
      signerAddress === currentAdmin,
      'the passed signer is not the admin, cannot update implementation'
    )

58 59 60 61 62 63
    let tx: ethers.providers.TransactionResponse
    if (!postUpgradeCallCalldata) {
      console.log(
        'postUpgradeCallCalldata is not provided. Using Proxy.upgrade()'
      )
      // Point the proxy to the target implementation
64
      tx = await proxyContract.connect(signer).upgradeTo(targetImplAddress)
65 66 67 68 69 70 71
    } else {
      console.log(
        'postUpgradeCallCalldata is provided. Using Proxy.upgradeAndCall()'
      )
      // Point the proxy to the target implementation,
      // and call function in the proxy's context
      tx = await proxyContract
72
        .connect(signer)
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
        .upgradeToAndCall(targetImplAddress, postUpgradeCallCalldata)
    }

    const receipt = await tx.wait()

    console.log(`implementation set in ${receipt.transactionHash}`)
  } else {
    console.log(`implementation already set correctly to ${targetImplAddress}`)
  }

  console.log(`admin set to ${currentAdmin}`)
  if (getAddress(currentAdmin) !== getAddress(targetProxyOwnerAddress)) {
    // If the proxy admin isn't the l2ProxyOwnerAddress, we need to update it
    // We're assuming that the proxy admin is the ddd right now.

    console.log('detected admin is not set correctly')
    console.log(`Setting admin to ${targetProxyOwnerAddress}`)

91 92 93 94 95 96 97
    // The signer needs to be the current admin, otherwise we don't have permission
    // to update the implmentation or admin
    assert(
      signerAddress === currentAdmin,
      'proxyOwnerSigner is not the admin, cannot update admin'
    )

98 99
    // change admin to the l2ProxyOwnerAddress
    const tx = await proxyContract
100
      .connect(signer)
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
      .changeAdmin(targetProxyOwnerAddress)

    const receipt = await tx.wait()

    console.log(`admin set in ${receipt.transactionHash}`)
  } else {
    console.log(`admin already set correctly to ${targetProxyOwnerAddress}`)
  }

  const updatedImplementation = await proxyContract
    .connect(ethers.constants.AddressZero)
    .callStatic.implementation()

  const updatedAdmin = await proxyContract
    .connect(ethers.constants.AddressZero)
    .callStatic.admin()

  assert(
    getAddress(updatedAdmin) === getAddress(targetProxyOwnerAddress),
    'Something went wrong - admin not set correctly after transaction'
  )
  assert(
    getAddress(updatedImplementation) === getAddress(targetImplAddress),
    'Something went wrong - implementation not set correctly after transaction'
  )

  console.log(
    `Proxy at ${proxyContract.address} is set up with implementation: ${updatedImplementation} and admin: ${updatedAdmin}`
  )
}

export { setupProxyContract }