diff --git a/debug.sh b/debug.sh index f09e41d..55a2636 100755 --- a/debug.sh +++ b/debug.sh @@ -7,7 +7,7 @@ fi verify_arg="" extra_argument="" -op_command="" +op_command="op run --env-file="./.env" --" for arg in "$@"; do case $arg in @@ -36,4 +36,4 @@ echo Value: ${VALUE} echo Calldata: cast pretty-calldata ${CALLDATA} calldata=$(cast calldata 'trace(uint256,address,address,uint256,bytes)' ${BLOCK} ${FROM} ${TO} ${VALUE} ${CALLDATA}) -${op_command} forge script ${verify_arg} --legacy ${@} script/OnchainDebugger.s.sol --sig 'run(bytes,string)' ${calldata} "${extra_argument}" +${op_command} forge script ${verify_arg} --legacy ${@} OnchainDebugger --sig 'run(bytes,string)' ${calldata} "${extra_argument}" diff --git a/script/BaseMigration.s.sol b/script/BaseMigration.s.sol index 72b5263..888d369 100644 --- a/script/BaseMigration.s.sol +++ b/script/BaseMigration.s.sol @@ -9,6 +9,7 @@ import { import { LibString } from "../lib/solady/src/utils/LibString.sol"; import { console, LibSharedAddress, StdStyle, IScriptExtended, ScriptExtended } from "./extensions/ScriptExtended.s.sol"; import { IArtifactFactory, ArtifactFactory } from "./ArtifactFactory.sol"; +import { OnchainDebugger } from "./OnchainDebugger.s.sol"; // cheat to load artifact to parent `out` directory import { IMigrationScript } from "./interfaces/IMigrationScript.sol"; import { LibProxy } from "./libraries/LibProxy.sol"; import { DefaultContract } from "./utils/DefaultContract.sol"; @@ -166,12 +167,7 @@ abstract contract BaseMigration is ScriptExtended { _mockUpgradeRaw(proxy.getProxyAdmin(), proxy, logic, args); } - function _upgradeProxy(TContract contractType) - internal - virtual - logFn(string.concat("_upgradeProxy ", TContract.unwrap(contractType).unpackOne())) - returns (address payable proxy) - { + function _upgradeProxy(TContract contractType) internal virtual returns (address payable proxy) { proxy = _upgradeProxy(contractType, arguments()); } @@ -190,41 +186,73 @@ abstract contract BaseMigration is ScriptExtended { internal virtual { + ITransparentUpgradeableProxy iProxy = ITransparentUpgradeableProxy(proxy); + ProxyAdmin wProxyAdmin = ProxyAdmin(proxyAdmin); + // if proxyAdmin is External Owned Wallet if (proxyAdmin.code.length == 0) { vm.prank(proxyAdmin); - if (args.length == 0) ITransparentUpgradeableProxy(proxy).upgradeTo(logic); - else ITransparentUpgradeableProxy(proxy).upgradeToAndCall(logic, args); + if (args.length == 0) iProxy.upgradeTo(logic); + else iProxy.upgradeToAndCall(logic, args); } else { - try ProxyAdmin(proxyAdmin).owner() returns (address owner) { - vm.prank(owner); + try wProxyAdmin.owner() returns (address owner) { if (args.length == 0) { - ProxyAdmin(proxyAdmin).upgrade(ITransparentUpgradeableProxy(proxy), logic); + // try `upgrade` function + vm.prank(owner); + (bool success,) = proxyAdmin.call(abi.encodeCall(ProxyAdmin.upgrade, (iProxy, logic))); + if (success) { + vm.prank(owner); + wProxyAdmin.upgrade(iProxy, logic); + } else { + console.log( + StdStyle.yellow( + "`ProxyAdmin:upgrade` failed!. Retrying with `ProxyAdmin:upgradeAndCall` with emty args..." + ) + ); + vm.prank(owner); + wProxyAdmin.upgradeAndCall(iProxy, logic, args); + } } else { - ProxyAdmin(proxyAdmin).upgradeAndCall(ITransparentUpgradeableProxy(proxy), logic, args); + vm.prank(owner); + wProxyAdmin.upgradeAndCall(iProxy, logic, args); } } catch { - vm.prank(proxyAdmin); - if (args.length == 0) ITransparentUpgradeableProxy(proxy).upgradeTo(logic); - else ITransparentUpgradeableProxy(proxy).upgradeToAndCall(logic, args); + revert("BaseMigration: Unknown ProxyAdmin contract!"); } } } function _upgradeRaw(address proxyAdmin, address payable proxy, address logic, bytes memory args) internal virtual { + ITransparentUpgradeableProxy iProxy = ITransparentUpgradeableProxy(proxy); + ProxyAdmin wProxyAdmin = ProxyAdmin(proxyAdmin); + // if proxyAdmin is External Owned Wallet if (proxyAdmin.code.length == 0) { vm.broadcast(proxyAdmin); - if (args.length == 0) ITransparentUpgradeableProxy(proxy).upgradeTo(logic); - else ITransparentUpgradeableProxy(proxy).upgradeToAndCall(logic, args); + if (args.length == 0) iProxy.upgradeTo(logic); + else iProxy.upgradeToAndCall(logic, args); } else { - try ProxyAdmin(proxyAdmin).owner() returns (address owner) { - vm.broadcast(owner); + try wProxyAdmin.owner() returns (address owner) { if (args.length == 0) { - ProxyAdmin(proxyAdmin).upgrade(ITransparentUpgradeableProxy(proxy), logic); + // try `upgrade` function + vm.prank(owner); + (bool success,) = proxyAdmin.call(abi.encodeCall(ProxyAdmin.upgrade, (iProxy, logic))); + if (success) { + vm.broadcast(owner); + wProxyAdmin.upgrade(iProxy, logic); + } else { + console.log( + StdStyle.yellow( + "`ProxyAdmin:upgrade` failed!. Retrying with `ProxyAdmin:upgradeAndCall` with emty args..." + ) + ); + vm.broadcast(owner); + wProxyAdmin.upgradeAndCall(iProxy, logic, args); + } } else { - ProxyAdmin(proxyAdmin).upgradeAndCall(ITransparentUpgradeableProxy(proxy), logic, args); + vm.broadcast(owner); + wProxyAdmin.upgradeAndCall(iProxy, logic, args); } } catch { - revert("BaseMigration: Unhandled case for upgrading proxy!"); + revert("BaseMigration: Unknown ProxyAdmin contract!"); } } } diff --git a/script/configs/WalletConfig.sol b/script/configs/WalletConfig.sol index d690afc..8aafef6 100644 --- a/script/configs/WalletConfig.sol +++ b/script/configs/WalletConfig.sol @@ -10,6 +10,10 @@ abstract contract WalletConfig is IWalletConfig { function getSender() public view virtual returns (address payable sender); + function getSenderPk() public view virtual returns (uint256) { + return _envPk; + } + function trezorPrefix() public view virtual returns (string memory) { return "trezor://"; } diff --git a/script/extensions/ScriptExtended.s.sol b/script/extensions/ScriptExtended.s.sol index a67be98..052e091 100644 --- a/script/extensions/ScriptExtended.s.sol +++ b/script/extensions/ScriptExtended.s.sol @@ -20,7 +20,7 @@ abstract contract ScriptExtended is Script, StdAssertions, IScriptExtended { console.log("> ", StdStyle.blue(fnName), "..."); _; } - + modifier onlyOn(TNetwork networkType) { require(network() == networkType, string.concat("ScriptExtended: Only allowed on ", CONFIG.getAlias(networkType))); _; @@ -33,10 +33,13 @@ abstract contract ScriptExtended is Script, StdAssertions, IScriptExtended { function _configByteCode() internal virtual returns (bytes memory); + function _postCheck() internal virtual { } + function run(bytes calldata callData, string calldata command) public virtual { CONFIG.resolveCommand(command); (bool success, bytes memory data) = address(this).delegatecall(callData); success.handleRevert(msg.sig, data); + _postCheck(); } function network() public view virtual returns (TNetwork) { diff --git a/script/interfaces/configs/IWalletConfig.sol b/script/interfaces/configs/IWalletConfig.sol index 86879aa..1532dfa 100644 --- a/script/interfaces/configs/IWalletConfig.sol +++ b/script/interfaces/configs/IWalletConfig.sol @@ -2,6 +2,8 @@ pragma solidity ^0.8.19; interface IWalletConfig { + function getSenderPk() external view returns (uint256); + function getSender() external view returns (address payable sender); function trezorPrefix() external view returns (string memory); diff --git a/script/libraries/LibProxy.sol b/script/libraries/LibProxy.sol index b4dee57..77198c1 100644 --- a/script/libraries/LibProxy.sol +++ b/script/libraries/LibProxy.sol @@ -9,19 +9,29 @@ library LibProxy { bytes32 internal constant ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; bytes32 internal constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; - function getProxyAdmin(address payable proxy) internal returns (address payable proxyAdmin) { + function getProxyAdmin(address payable proxy, bool nullCheck) internal returns (address payable proxyAdmin) { proxyAdmin = payable(address(uint160(uint256(vm.load(address(proxy), ADMIN_SLOT))))); + if (!nullCheck) return proxyAdmin; require( proxyAdmin != address(0x0), string.concat("LibProxy: Null ProxyAdmin, Provided address: ", vm.getLabel(proxy), " is not EIP1967 Proxy") ); } - function getProxyImplementation(address payable proxy) internal returns (address payable impl) { + function getProxyAdmin(address payable proxy) internal returns (address payable proxyAdmin) { + proxyAdmin = getProxyAdmin({ proxy: proxy, nullCheck: true }); + } + + function getProxyImplementation(address payable proxy, bool nullCheck) internal returns (address payable impl) { impl = payable(address(uint160(uint256(vm.load(address(proxy), IMPLEMENTATION_SLOT))))); + if (!nullCheck) return impl; require( impl != address(0x0), string.concat("LibProxy: Null Implementation, Provided address: ", vm.getLabel(proxy), " is not EIP1967 Proxy") ); } + + function getProxyImplementation(address payable proxy) internal returns (address payable impl) { + impl = getProxyImplementation({ proxy: proxy, nullCheck: true }); + } } diff --git a/src/WNT.sol b/src/WNT.sol index 28cb8ce..6331eaf 100644 --- a/src/WNT.sol +++ b/src/WNT.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.17; import { ERC20 } from "../lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol"; import { IWNT } from "./interfaces/IWNT.sol"; -import { LibNativeTransfer } from "./libraries/LibNativeTransfer.sol"; +import { LibNativeTransfer } from "contract-libs/transfers/LibNativeTransfer.sol"; /// @notice Minimalist and modern Wrapped Ether implementation. /// @author Solmate diff --git a/src/libraries/LibErrorHandler.sol b/src/libraries/LibErrorHandler.sol deleted file mode 100644 index 8202fca..0000000 --- a/src/libraries/LibErrorHandler.sol +++ /dev/null @@ -1,40 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.19; - -library LibErrorHandler { - /// @dev Reserves error definition to upload to signature database. - error ExternalCallFailed(bytes4 msgSig, bytes4 callSig); - - /// @notice handle low level call revert if call failed, - /// If extcall return empty bytes, reverts with custom error. - /// @param status Status of external call - /// @param callSig function signature of the calldata - /// @param returnOrRevertData bytes result from external call - function handleRevert(bool status, bytes4 callSig, bytes memory returnOrRevertData) internal pure { - // Get the function signature of current context - bytes4 msgSig = msg.sig; - assembly ("memory-safe") { - if iszero(status) { - // Load the length of bytes array - let revertLength := mload(returnOrRevertData) - // Check if length != 0 => revert following reason from external call - if iszero(iszero(revertLength)) { - // Start of revert data bytes. The 0x20 offset is always the same. - revert(add(returnOrRevertData, 0x20), revertLength) - } - - // Load free memory pointer - let ptr := mload(0x40) - // Store 4 bytes the function selector of ExternalCallFailed(msg.sig, callSig) - // Equivalent to revert ExternalCallFailed(bytes4,bytes4) - mstore(ptr, 0x49bf4104) - // Store 4 bytes of msgSig parameter in the next slot - mstore(add(ptr, 0x20), msgSig) - // Store 4 bytes of callSig parameter in the next slot - mstore(add(ptr, 0x40), callSig) - // Revert 68 bytes of error starting from 0x1c - revert(add(ptr, 0x1c), 0x44) - } - } - } -} diff --git a/src/libraries/LibNativeTransfer.sol b/src/libraries/LibNativeTransfer.sol deleted file mode 100644 index 6e5a330..0000000 --- a/src/libraries/LibNativeTransfer.sol +++ /dev/null @@ -1,36 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -import { LibErrorHandler } from "./LibErrorHandler.sol"; - -/** - * @title NativeTransferHelper - */ -library LibNativeTransfer { - using LibErrorHandler for bool; - - /** - * @dev Transfers Native Coin and wraps result for the method caller to a recipient. - */ - function transfer(address to, uint256 value, uint256 gasAmount) internal { - (bool success, bytes memory returnOrRevertData) = trySendValue(to, value, gasAmount); - success.handleRevert(bytes4(0x0), returnOrRevertData); - } - - /** - * @dev Unsafe send `amount` Native to the address `to`. If the sender's balance is insufficient, - * the call does not revert. - * - * Note: - * - Does not assert whether the balance of sender is sufficient. - * - Does not assert whether the recipient accepts NATIVE. - * - Consider using `ReentrancyGuard` before calling this function. - * - */ - function trySendValue(address to, uint256 value, uint256 gasAmount) - internal - returns (bool success, bytes memory returnOrRevertData) - { - (success, returnOrRevertData) = to.call{ value: value, gas: gasAmount }(""); - } -}