Skip to content

Commit

Permalink
ethereum: Implement shutdown for all 3 contracts (fixes #1937)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
Csongor Kiss authored and kcsongor committed Nov 23, 2022
1 parent 648b361 commit effde7f
Show file tree
Hide file tree
Showing 14 changed files with 171 additions and 19 deletions.
31 changes: 31 additions & 0 deletions ethereum/contracts/Shutdown.sol
Original file line number Diff line number Diff line change
@@ -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.
}
}
36 changes: 36 additions & 0 deletions ethereum/contracts/bridge/BridgeShutdown.sol
Original file line number Diff line number Diff line change
@@ -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.
}
}
4 changes: 2 additions & 2 deletions ethereum/contracts/nft/NFTBridge.sol
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// contracts/Bridge.sol
// contracts/NFTBridge.sol
// SPDX-License-Identifier: Apache 2

pragma solidity ^0.8.0;
Expand Down Expand Up @@ -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));
Expand Down
2 changes: 1 addition & 1 deletion ethereum/contracts/nft/NFTBridgeGetters.sol
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// contracts/Getters.sol
// contracts/NFTBridgeGetters.sol
// SPDX-License-Identifier: Apache 2

pragma solidity ^0.8.0;
Expand Down
2 changes: 1 addition & 1 deletion ethereum/contracts/nft/NFTBridgeGovernance.sol
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// contracts/Bridge.sol
// contracts/NFTBridgeGovernance.sol
// SPDX-License-Identifier: Apache 2

pragma solidity ^0.8.0;
Expand Down
2 changes: 1 addition & 1 deletion ethereum/contracts/nft/NFTBridgeImplementation.sol
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// contracts/Implementation.sol
// contracts/NFTBridgeImplementation.sol
// SPDX-License-Identifier: Apache 2

pragma solidity ^0.8.0;
Expand Down
2 changes: 1 addition & 1 deletion ethereum/contracts/nft/NFTBridgeSetters.sol
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// contracts/Setters.sol
// contracts/NFTBridgeSetters.sol
// SPDX-License-Identifier: Apache 2

pragma solidity ^0.8.0;
Expand Down
2 changes: 1 addition & 1 deletion ethereum/contracts/nft/NFTBridgeSetup.sol
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// contracts/BridgeSetup.sol
// contracts/NFTBridgeSetup.sol
// SPDX-License-Identifier: Apache 2

pragma solidity ^0.8.0;
Expand Down
30 changes: 30 additions & 0 deletions ethereum/contracts/nft/NFTBridgeShutdown.sol
Original file line number Diff line number Diff line change
@@ -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.
}
}
11 changes: 11 additions & 0 deletions ethereum/scripts/deploy_core_bridge_shutdown.js
Original file line number Diff line number Diff line change
@@ -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);
}
};
11 changes: 11 additions & 0 deletions ethereum/scripts/deploy_nft_bridge_shutdown.js
Original file line number Diff line number Diff line change
@@ -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);
}
};
11 changes: 11 additions & 0 deletions ethereum/scripts/deploy_token_bridge_shutdown.js
Original file line number Diff line number Diff line change
@@ -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);
}
};
28 changes: 22 additions & 6 deletions ethereum/simulate_upgrade
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
}
Expand All @@ -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
;;
Expand All @@ -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
;;
Expand Down Expand Up @@ -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
Expand Down
18 changes: 12 additions & 6 deletions ethereum/simulate_upgrades
Original file line number Diff line number Diff line change
Expand Up @@ -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

0 comments on commit effde7f

Please sign in to comment.