diff --git a/script/upgrades/v2.0.3/Upgrade.s.sol b/script/upgrades/v2.1.0/Upgrade.s.sol similarity index 97% rename from script/upgrades/v2.0.3/Upgrade.s.sol rename to script/upgrades/v2.1.0/Upgrade.s.sol index 0ea9219c..7a831c2c 100644 --- a/script/upgrades/v2.0.3/Upgrade.s.sol +++ b/script/upgrades/v2.1.0/Upgrade.s.sol @@ -33,12 +33,12 @@ import { OPTIMISM_GOERLI_UNISWAP_UNIVERSAL_ROUTER } from "script/utils/parameters/OptimismGoerliParameters.sol"; -/// @title Script to upgrade the Account implementation v2.0.2 -> v2.0.3 +/// @title Script to upgrade the Account implementation v2.0.2 -> v2.1.0 /// @author JaredBorders (jaredborders@pm.me) /// @dev steps to deploy and verify on Optimism: /// (1) load the variables in the .env file via `source .env` -/// (2) run `forge script script/upgrades/v2.0.3/Upgrade.s.sol:UpgradeAccountOptimism --rpc-url $ARCHIVE_NODE_URL_L2 --broadcast --verify -vvvv` +/// (2) run `forge script script/upgrades/v2.1.0/Upgrade.s.sol:UpgradeAccountOptimism --rpc-url $ARCHIVE_NODE_URL_L2 --broadcast --verify -vvvv` /// (3) Smart Margin Account Factory owner (i.e. Kwenta pDAO) will need to call `upgradeAccountImplementation` on the Factory with the address of the new Account implementation contract UpgradeAccountOptimism is Script { function run() public { @@ -92,7 +92,7 @@ contract UpgradeAccountOptimism is Script { /// @dev steps to deploy and verify on Optimism Goerli: /// (1) load the variables in the .env file via `source .env` -/// (2) run `forge script script/upgrades/v2.0.3/Upgrade.s.sol:UpgradeAccountOptimismGoerli --rpc-url $ARCHIVE_NODE_URL_GOERLI_L2 --broadcast --verify -vvvv` +/// (2) run `forge script script/upgrades/v2.1.0/Upgrade.s.sol:UpgradeAccountOptimismGoerli --rpc-url $ARCHIVE_NODE_URL_GOERLI_L2 --broadcast --verify -vvvv` /// (3) Smart Margin Account Factory owner (i.e. Kwenta pDAO) will need to call `upgradeAccountImplementation` on the Factory with the address of the new Account implementation contract UpgradeAccountOptimismGoerli is Script { function run() public { diff --git a/src/Account.sol b/src/Account.sol index c2bdff45..c972d501 100644 --- a/src/Account.sol +++ b/src/Account.sol @@ -238,6 +238,7 @@ contract Account is IAccount, Auth, OpsReady { external payable override + nonReentrant isAccountExecutionEnabled { uint256 numCommands = _commands.length; @@ -257,10 +258,7 @@ contract Account is IAccount, Auth, OpsReady { /// @notice Decodes and executes the given command with the given inputs /// @param _command: The command type to execute /// @param _inputs: The inputs to execute the command with - function _dispatch(Command _command, bytes calldata _inputs) - internal - nonReentrant - { + function _dispatch(Command _command, bytes calldata _inputs) internal { uint256 commandIndex = uint256(_command); if (commandIndex < 4) { @@ -909,7 +907,7 @@ contract Account is IAccount, Auth, OpsReady { _transfer({_amount: fee}); } else { fee = SETTINGS.executorFee(); - (bool success,) = payable(msg.sender).call{value: fee}(""); + (bool success,) = msg.sender.call{value: fee}(""); if (!success) revert CannotPayExecutorFee(fee, msg.sender); } } @@ -1023,6 +1021,12 @@ contract Account is IAccount, Auth, OpsReady { _sufficientMargin(int256(_amountIn)); recipient = msg.sender; + + // transfer sUSD to the UniversalRouter for the swap + /// @dev not using SafeERC20 because sUSD is a trusted token + IERC20(tokenIn).transfer( + address(UNISWAP_UNIVERSAL_ROUTER), _amountIn + ); } else if ( tokenOut == address(MARGIN_ASSET) && SETTINGS.isWhitelistedTokens(tokenIn) @@ -1031,7 +1035,7 @@ contract Account is IAccount, Auth, OpsReady { /// @dev msg.sender must have approved Permit2 to spend at least the amountIn PERMIT2.transferFrom({ from: msg.sender, - to: address(this), + to: address(UNISWAP_UNIVERSAL_ROUTER), amount: _amountIn.toUint160(), token: tokenIn }); @@ -1042,18 +1046,6 @@ contract Account is IAccount, Auth, OpsReady { revert TokenSwapNotAllowed(tokenIn, tokenOut); } - // approve Permit2 to spend _amountIn of this contract's tokenIn - IERC20(tokenIn).approve(address(PERMIT2), _amountIn); - - // approve tokens to be swapped via Universal Router - PERMIT2.approve({ - token: tokenIn, - spender: address(UNISWAP_UNIVERSAL_ROUTER), - amount: _amountIn.toUint160(), - /// @dev timstamp will never overflow (i.e. maximum value of uint48 is year 8 million 921 thousand 556) - expiration: uint48(block.timestamp) - }); - _universalRouterExecute(recipient, _amountIn, _amountOutMin, _path); EVENTS.emitUniswapV3Swap({ @@ -1099,15 +1091,15 @@ contract Account is IAccount, Auth, OpsReady { uint256 _amountOutMin, bytes calldata _path ) internal { - /// @dev payerIsUser (i.e. 5th argument encoded) will always be true + /// @dev payerIsUser (i.e. 5th argument encoded) will always be false because + /// tokens are transferred to the UniversalRouter before executing the swap bytes[] memory inputs = new bytes[](1); inputs[0] = - abi.encode(_recipient, _amountIn, _amountOutMin, _path, true); + abi.encode(_recipient, _amountIn, _amountOutMin, _path, false); UNISWAP_UNIVERSAL_ROUTER.execute({ commands: abi.encodePacked(bytes1(uint8(V3_SWAP_EXACT_IN))), inputs: inputs - /// @custom:auditor removed deadline here and want increased scrutiny }); } diff --git a/src/Events.sol b/src/Events.sol index 43593ca5..78d79a1e 100644 --- a/src/Events.sol +++ b/src/Events.sol @@ -143,13 +143,4 @@ contract Events is IEvents { priceOracle: priceOracle }); } - - /// @inheritdoc IEvents - function emitExecutorFeeSet(uint256 executorFee) - external - override - onlyAccounts - { - emit ExecutorFeeSet({account: msg.sender, executorFee: executorFee}); - } } diff --git a/src/interfaces/IEvents.sol b/src/interfaces/IEvents.sol index a2c3dbff..ded3db16 100644 --- a/src/interfaces/IEvents.sol +++ b/src/interfaces/IEvents.sol @@ -147,10 +147,4 @@ interface IEvents { uint256 keeperFee, IAccount.PriceOracleUsed priceOracle ); - - /// @notice emitter when executor fee is set by the account owner - /// @param executorFee: executor fee - function emitExecutorFeeSet(uint256 executorFee) external; - - event ExecutorFeeSet(address indexed account, uint256 indexed executorFee); } diff --git a/src/utils/uniswap/V3Path.sol b/src/utils/uniswap/V3Path.sol index 2ad0b9dc..5dc594da 100644 --- a/src/utils/uniswap/V3Path.sol +++ b/src/utils/uniswap/V3Path.sol @@ -2,7 +2,7 @@ pragma solidity 0.8.18; import {BytesLib} from "src/utils/uniswap/BytesLib.sol"; -import {Constants} from "src/utils/uniswap//Constants.sol"; +import {Constants} from "src/utils/uniswap/Constants.sol"; /// @title Functions for manipulating path data for multihop swaps library V3Path { diff --git a/test/upgrades/v2.0.3/Upgrade.t.sol b/test/upgrades/v2.1.0/Upgrade.t.sol similarity index 97% rename from test/upgrades/v2.0.3/Upgrade.t.sol rename to test/upgrades/v2.1.0/Upgrade.t.sol index 1a780f78..ca1f7867 100644 --- a/test/upgrades/v2.0.3/Upgrade.t.sol +++ b/test/upgrades/v2.1.0/Upgrade.t.sol @@ -3,7 +3,7 @@ pragma solidity 0.8.18; import {Test} from "lib/forge-std/src/Test.sol"; -import {UpgradeAccountOptimism} from "script/upgrades/v2.0.3/Upgrade.s.sol"; +import {UpgradeAccountOptimism} from "script/upgrades/v2.1.0/Upgrade.s.sol"; import { OPTIMISM_FACTORY, OPTIMISM_PDAO, @@ -14,7 +14,7 @@ import {Factory} from "src/Factory.sol"; import {IAccount as OldAccount} from "test/upgrades/v2.0.2/interfaces/IAccount.sol"; import {IAccount as NewAccount} from - "test/upgrades/v2.0.3/interfaces/IAccount.sol"; + "test/upgrades/v2.1.0/interfaces/IAccount.sol"; import {IERC20} from "src/interfaces/token/IERC20.sol"; import {ISynth} from "test/utils/interfaces/ISynth.sol"; @@ -36,7 +36,7 @@ contract UpgradeTest is Test { 0x3BC8D34314E77c2E36948Fd8F4B353f1baDc3F6C; /*////////////////////////////////////////////////////////////// - V2.0.3 IMPLEMENTATION + V2.1.0 IMPLEMENTATION //////////////////////////////////////////////////////////////*/ address private NEW_IMPLEMENTATION; @@ -61,7 +61,7 @@ contract UpgradeTest is Test { UpgradeAccountOptimism upgradeAccountOptimism = new UpgradeAccountOptimism(); - // deploy v2.0.3 implementation + // deploy v2.1.0 implementation address implementationAddr = upgradeAccountOptimism.upgrade(); NEW_IMPLEMENTATION = payable(implementationAddr); } @@ -121,7 +121,7 @@ contract UpgradeTest is Test { * EXECUTE UPGRADE */ - // upgrade Active Account to v2.0.3 + // upgrade Active Account to v2.1.0 vm.prank(OPTIMISM_PDAO); Factory(OPTIMISM_FACTORY).upgradeAccountImplementation( address(NEW_IMPLEMENTATION) diff --git a/test/upgrades/v2.0.3/interfaces/IAccount.sol b/test/upgrades/v2.1.0/interfaces/IAccount.sol similarity index 99% rename from test/upgrades/v2.0.3/interfaces/IAccount.sol rename to test/upgrades/v2.1.0/interfaces/IAccount.sol index 96c4fc93..fd8e1a8a 100644 --- a/test/upgrades/v2.0.3/interfaces/IAccount.sol +++ b/test/upgrades/v2.1.0/interfaces/IAccount.sol @@ -4,7 +4,7 @@ pragma solidity 0.8.18; import {IPerpsV2MarketConsolidated} from "src/interfaces/synthetix/IPerpsV2MarketConsolidated.sol"; -/// @title Kwenta Smart Margin Account v2.0.3 Implementation Interface +/// @title Kwenta Smart Margin Account v2.1.0 Implementation Interface /// @author JaredBorders (jaredborders@pm.me), JChiaramonte7 (jeremy@bytecode.llc) interface IAccount { /*/////////////////////////////////////////////////////////////// diff --git a/test/utils/ConsolidatedEvents.sol b/test/utils/ConsolidatedEvents.sol index 45d91147..8846cb75 100644 --- a/test/utils/ConsolidatedEvents.sol +++ b/test/utils/ConsolidatedEvents.sol @@ -85,8 +85,6 @@ contract ConsolidatedEvents { IAccount.PriceOracleUsed priceOracle ); - event ExecutorFeeSet(address indexed account, uint256 indexed executorFee); - /*////////////////////////////////////////////////////////////// ISETTINGS //////////////////////////////////////////////////////////////*/