ethereum: Implement shutdown for all 3 contracts (fixes #1937)

These are stripped down versions of the original contracts that can be
dropped in place via an upgrade to disable core functionality.
Governance features are still enabled, which means it's possible to
upgrade back to a working implementation.
This commit is contained in:
Csongor Kiss 2022-11-16 18:03:28 +00:00 committed by Csongor Kiss
parent 648b361623
commit effde7f756
14 changed files with 171 additions and 19 deletions

View File

@ -0,0 +1,31 @@
// contracts/Shutdown.sol
// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.0;
pragma experimental ABIEncoderV2;
import "./Governance.sol";
import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Upgrade.sol";
/**
* @title Shutdown
* @notice This contract implements a stripped-down version of the Wormhole core
* messaging protocol that is a drop-in replacement for Wormhole's
* implementation contract, effectively disabling all non-governance
* functionality.
* In particular, outgoing messages are disabled, but the contract
* remains upgradeable through governance.
*/
contract Shutdown is Governance {
function initialize() public {
address implementation = ERC1967Upgrade._getImplementation();
setInitialized(implementation);
// this function needs to be exposed for an upgrade to pass
// NOTE: leave this function empty! It specifically does not have an
// 'initializer' modifier, to allow this contract to be upgraded to
// multiple times.
}
}

View File

@ -0,0 +1,36 @@
// contracts/BridgeShutdown.sol
// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.0;
import "./BridgeGovernance.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Upgrade.sol";
/**
* @title BridgeShutdown
* @notice This contract implements a stripped-down version of the token bridge
* asset transfer protocol that is a drop-in replacement for the Bridge
* implementation contract, effectively disabling all non-governance
* functionality.
* In particular, sending and receiving assets is disabled, but the
* contract remains upgradeable through governance.
* @dev Technically the ReentrancyGuard is not used in this contract,
* but it adds a storage variable, so as a matter of principle, we
* inherit that here too in order keep the storage layout identical to
* the actual implementation contract (which does use the reentrancy
* guard).
*/
contract BridgeShutdown is BridgeGovernance, ReentrancyGuard {
function initialize() public {
address implementation = ERC1967Upgrade._getImplementation();
setInitialized(implementation);
// this function needs to be exposed for an upgrade to pass
// NOTE: leave this function empty! It specifically does not have an
// 'initializer' modifier, to allow this contract to be upgraded to
// multiple times.
}
}

View File

@ -1,4 +1,4 @@
// contracts/Bridge.sol
// contracts/NFTBridge.sol
// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.0;
@ -241,7 +241,7 @@ contract NFTBridge is NFTBridgeGovernance {
transfer.tokenID = encoded.toUint256(index);
index += 32;
// Ignore length due to malformatted payload
index += 1;
transfer.uri = string(encoded.slice(index, encoded.length - index - 34));

View File

@ -1,4 +1,4 @@
// contracts/Getters.sol
// contracts/NFTBridgeGetters.sol
// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.0;

View File

@ -1,4 +1,4 @@
// contracts/Bridge.sol
// contracts/NFTBridgeGovernance.sol
// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.0;

View File

@ -1,4 +1,4 @@
// contracts/Implementation.sol
// contracts/NFTBridgeImplementation.sol
// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.0;

View File

@ -1,4 +1,4 @@
// contracts/Setters.sol
// contracts/NFTBridgeSetters.sol
// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.0;

View File

@ -1,4 +1,4 @@
// contracts/BridgeSetup.sol
// contracts/NFTBridgeSetup.sol
// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.0;

View File

@ -0,0 +1,30 @@
// contracts/NFTBridgeShutdown.sol
// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.0;
import "./NFTBridgeGovernance.sol";
import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Upgrade.sol";
/**
* @title BridgeShutdown
* @notice This contract implements a stripped-down version of the NFT bridge
* asset transfer protocol that is a drop-in replacement for the
* NFTBridge implementation contract, effectively disabling all
* non-governance functionality.
* In particular, sending and receiving assets is disabled, but the
* contract remains upgradeable through governance.
*/
contract NFTBridgeShutdown is NFTBridgeGovernance {
function initialize() public {
address implementation = ERC1967Upgrade._getImplementation();
setInitialized(implementation);
// this function needs to be exposed for an upgrade to pass
// NOTE: leave this function empty! It specifically does not have an
// 'initializer' modifier, to allow this contract to be upgraded to
// multiple times.
}
}

View File

@ -0,0 +1,11 @@
const Shutdown = artifacts.require("Shutdown");
module.exports = async function(callback) {
try {
const contract = (await Shutdown.new());
console.log('tx: ' + contract.transactionHash);
console.log('Shutdown address: ' + contract.address);
callback();
} catch (e) {
callback(e);
}
};

View File

@ -0,0 +1,11 @@
const Shutdown = artifacts.require("NFTBridgeShutdown");
module.exports = async function(callback) {
try {
const contract = (await Shutdown.new());
console.log('tx: ' + contract.transactionHash);
console.log('NFTBridgeShutdown address: ' + contract.address);
callback();
} catch (e) {
callback(e);
}
};

View File

@ -0,0 +1,11 @@
const Shutdown = artifacts.require("BridgeShutdown");
module.exports = async function(callback) {
try {
const contract = (await Shutdown.new());
console.log('tx: ' + contract.transactionHash);
console.log('Bridge address: ' + contract.address);
callback();
} catch (e) {
callback(e);
}
};

View File

@ -15,7 +15,7 @@ function usage() {
cat <<EOF >&2
Usage:
$(basename "$0") [-h] [-m s] [-c s] [-x] [-k] [-d] [-a s] [-l s] -- Simulate an upgrade on a fork of mainnet, and check for any errors.
$(basename "$0") [-h] [-m s] [-c s] [-x] [-k] [-d] [-a s] [-l s] [-s] -- Simulate an upgrade on a fork of mainnet, and check for any errors.
where:
-h show this help text
@ -24,8 +24,9 @@ Usage:
-x run anvil
-d don't compile contract first
-k keep anvil alive
-l file to loge to (by default creates a new tmp file)
-l file to log to (by default creates a new tmp file)
-a new code address (by default it builds the most recent contract in the repository)
-s shutdown
EOF
exit 1
}
@ -40,8 +41,9 @@ chain_name=""
run_anvil=false
skip_compile=false
keepalive_anvil=false
shutdown=false
anvil_out=$(mktemp)
while getopts ':hm:c:a:xkdl:' option; do
while getopts ':hm:c:a:xkdl:s' option; do
case "$option" in
h) usage
;;
@ -60,6 +62,8 @@ while getopts ':hm:c:a:xkdl:' option; do
k) keepalive_anvil=true
run_anvil=true
;;
s) shutdown=true
;;
:) printf "missing argument for -%s\n" "$OPTARG" >&2
usage
;;
@ -111,15 +115,27 @@ SCRIPT=""
case "$module" in
bridge|core)
MODULE=Core
SCRIPT="scripts/deploy_core_bridge.js"
if [[ $shutdown = true ]]; then
SCRIPT="scripts/deploy_core_bridge_shutdown.js"
else
SCRIPT="scripts/deploy_core_bridge.js"
fi
;;
token_bridge)
MODULE=TokenBridge
SCRIPT="scripts/deploy_token_bridge.js"
if [[ $shutdown = true ]]; then
SCRIPT="scripts/deploy_token_bridge_shutdown.js"
else
SCRIPT="scripts/deploy_token_bridge.js"
fi
;;
nft_bridge)
MODULE=NFTBridge
SCRIPT="scripts/deploy_nft_bridge.js"
if [[ $shutdown = true ]]; then
SCRIPT="scripts/deploy_nft_bridge_shutdown.js"
else
SCRIPT="scripts/deploy_nft_bridge.js"
fi
;;
*) echo "unknown module $module" >&2
usage

View File

@ -28,17 +28,23 @@ ANVIL_PID=$!
# Sleep for 10 seconds here to give some time for the fork to complete.
sleep 10
echo "========================= Updating core contract #1 ============================"
echo "========================= Updating core contract ============================"
./simulate_upgrade -m bridge -c $chain -d
echo "========================= Updating core contract #2 ============================"
echo "========================= Shutting down core contract ======================="
./simulate_upgrade -m bridge -c $chain -d -s
echo "========================= Re-enabling core contract ========================="
./simulate_upgrade -m bridge -c $chain -d
echo "===================== Updating token bridge contract #1 ========================"
echo "===================== Updating token bridge contract ========================"
./simulate_upgrade -m token_bridge -c $chain -d
echo "===================== Updating token bridge contract #2 ========================"
echo "===================== Shutting down token bridge contract ==================="
./simulate_upgrade -m token_bridge -c $chain -d -s
echo "===================== Re-enabling token bridge contract ====================="
./simulate_upgrade -m token_bridge -c $chain -d
echo "====================== Updating NFT bridge contract #1 ========================="
echo "====================== Updating NFT bridge contract ========================="
./simulate_upgrade -m nft_bridge -c $chain -d
echo "====================== Updating NFT bridge contract #2 ========================="
echo "====================== Shutting down NFT bridge contract ===================="
./simulate_upgrade -m nft_bridge -c $chain -d -s
echo "====================== Re-enabling NFT bridge contract ======================"
./simulate_upgrade -m nft_bridge -c $chain -d