Skip to content

Device is already in use by another transport when deploying a contract and then propose a tx #3

@bugduino

Description

@bugduino

I'm running into an issue while using a script really similar to the following:

pragma solidity >=0.8.28 <0.9.0;

import { Contract } from "../src/Contract.sol";
import { Script } from "forge-std/Script.sol";
import { console } from "forge-std/console.sol";
import { Upgrades, Options } from "@openzeppelin/foundry-upgrades/Upgrades.sol";
import { Safe } from "safe-utils/Safe.sol";
import { IProxyAdmin } from "@openzeppelin/foundry-upgrades/internal/interfaces/IProxyAdmin.sol";

contract DeployScript is Script {
  using Safe for *;
  error Invalid();

  string public constant BUILD_INFO_DIR = "old-build-info/";

  // Gnosis Safe instance
  Safe.Client safe;

  // Optimism test contracts
  string public constant network = "optimism";
  address public constant SAFE_ADDRESS = address(2); // CHANGE THIS
  address public constant PROXY = address(1); // CHANGE THIS 

  function run() public {
    vm.createSelectFork(network);
    vm.startBroadcast();
    console.log('Upgrading in', network);
    _upgradeContractMultisig();
    vm.stopBroadcast();
  }

  // Methods to propose an upgrade to the proxy implementation
  function _upgradeContractMultisig() internal {
    _upgradeViaMultisig(PROXY, "Contract");
  }
  
  /// @notice Prepares the upgrade of the proxy implementation to a new version.
  /// @param proxy The address of the proxy contract to upgrade.
  /// @param oldContract The name of the old contract to upgrade.
  function _upgradeViaMultisig(address proxy, string memory oldContract) public {
    if (proxy == address(0) || bytes(oldContract).length == 0) {
      revert Invalid();
    }
    safe.initialize(SAFE_ADDRESS);

    // https://github.com/OpenZeppelin/openzeppelin-foundry-upgrades?tab=readme-ov-file#upgrade-a-proxy-or-beacon
    Options memory opts;
    opts.referenceBuildInfoDir = string(abi.encodePacked(BUILD_INFO_DIR, network));
    opts.referenceContract = string(abi.encodePacked(network, ":", oldContract));
    string memory contractFile = string(abi.encodePacked(oldContract, ".sol"));

    // Validate and deploy new implementation
    address newImpl = Upgrades.prepareUpgrade(contractFile, opts);
    // Propose upgrade tx with multisig
    safe.proposeTransaction(
      Upgrades.getAdminAddress(proxy), 
      abi.encodeCall(IProxyAdmin.upgradeAndCall, (proxy, newImpl, "")), 
      DEPLOYER,
      "m/44'/60'/0'/0/0"
    );
  }
}

In my script I am deploying a new contract (in this case via Upgrades.prepareUpgrade(contractFile, opts) to deploy a new implementation contract for a proxy) and then I'm trying to propose a tx in the multisig to update the proxy. What I see is that it first triggers an error like below (I guess during the simulation step)

Image

stating that the Ledger is already in use basically.
What happens next is that the new implementation contract is deployed and verified normally but there is no prompt to sign the multisig tx and so the tx is not posted on the Safe.

Any idea why? Seems like some sort of race condition where the Ledger is used both for deploying and signing the Safe tx at the same time

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions