Skip to content

Commit

Permalink
🔒 Execution Lock Mechanism
Browse files Browse the repository at this point in the history
  • Loading branch information
JaredBorders committed Apr 27, 2023
2 parents e4ae09d + 438caef commit 71661a2
Show file tree
Hide file tree
Showing 22 changed files with 558 additions and 204 deletions.
218 changes: 114 additions & 104 deletions .gas-snapshot

Large diffs are not rendered by default.

25 changes: 14 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ Contracts to manage account abstractions and features on top of [Synthetix Perps
### System Diagram

<p align="center">
<img src="/diagrams/Abstract-System-Diagram.png" width="1000" height="400" alt="System-Diagram"/>
<img src="/diagrams/Abstract-System-Diagram.png" width="1000" height="600" alt="System-Diagram"/>
</p>

## Contracts Overview
Expand Down Expand Up @@ -106,16 +106,18 @@ src
├── AccountProxy.sol
├── Events.sol
├── Factory.sol
├── Settings.sol
├── interfaces
│   ├── IAccount.sol
│   ├── IAccountProxy.sol
│   ├── IEvents.sol
│   ├── IFactory.sol
│   ├── IOps.sol
│   └── synthetix
│   ├── IFuturesMarketManager.sol
│   ├── IPerpsV2MarketConsolidated.sol
│   └── ISystemStatus.sol
│ ├── IAccount.sol
│ ├── IAccountProxy.sol
│ ├── IEvents.sol
│ ├── IFactory.sol
│ ├── IOps.sol
│ ├── ISettings.sol
│ └── synthetix
│ ├── IFuturesMarketManager.sol
│ ├── IPerpsV2MarketConsolidated.sol
│ └── ISystemStatus.sol
└── utils
├── Auth.sol
└── OpsReady.sol
Expand All @@ -125,10 +127,11 @@ src

| File | % Lines | % Statements | % Branches | % Funcs |
|--------------------------------|------------------|------------------|-----------------|-----------------|
| src/Account.sol | 98.51% (199/202) | 98.60% (211/214) | 91.89% (68/74) | 100.00% (34/34) |
| src/Account.sol | 98.53% (201/204) | 98.61% (213/216) | 92.11% (70/76) | 100.00% (35/35) |
| src/AccountProxy.sol | 100.00% (10/10) | 76.92% (10/13) | 50.00% (3/6) | 100.00% (6/6) |
| src/Events.sol | 100.00% (6/6) | 100.00% (6/6) | 100.00% (0/0) | 100.00% (6/6) |
| src/Factory.sol | 100.00% (27/27) | 100.00% (34/34) | 85.71% (12/14) | 100.00% (6/6) |
| src/Settings.sol | 100.00% (2/2) | 100.00% (2/2) | 100.00% (0/0) | 100.00% (1/1) |
| src/utils/Auth.sol | 100.00% (15/15) | 100.00% (18/18) | 100.00% (10/10) | 100.00% (5/5) |
| src/utils/OpsReady.sol | 100.00% (3/3) | 100.00% (4/4) | 75.00% (3/4) | 100.00% (1/1) |

Expand Down
Binary file modified diagrams/Abstract-System-Diagram.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
106 changes: 36 additions & 70 deletions script/Deploy.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,12 @@
pragma solidity 0.8.18;

import "forge-std/Script.sol";
import "./utils/deploy-parameters.sol";
import {Account} from "src/Account.sol";
import {Events} from "src/Events.sol";
import {Factory} from "src/Factory.sol";

interface IAddressResolver {
function getAddress(bytes32 name) external view returns (address);
}
import {IAddressResolver} from "./utils/interfaces/IAddressResolver.sol";
import {Settings} from "src/Settings.sol";

/// @title Script to deploy Kwenta's Smart Margin Account Factory
/// @author JaredBorders (jaredborders@pm.me)
Expand All @@ -19,16 +18,33 @@ contract Setup {
address _addressResolver,
address _gelato,
address _ops
) public returns (Factory factory, Events events, Account implementation) {
)
public
returns (
Factory factory,
Events events,
Settings settings,
Account implementation
)
{
// define *initial* factory owner
address temporaryOwner =
_deployer == address(0) ? address(this) : _deployer;

// deploy the factory
factory = deploySmartMarginFactory({_owner: temporaryOwner});
factory = new Factory({
_owner: temporaryOwner
});

// deploy the events contract and set the factory
events = deployEvents({_factory: address(factory)});
events = new Events({
_factory: address(factory)
});

// deploy the settings contract
settings = new Settings({
_owner: _owner
});

// resolve necessary addresses via the Synthetix Address Resolver
IAddressResolver addressResolver = IAddressResolver(_addressResolver);
Expand All @@ -39,15 +55,15 @@ contract Setup {
address systemStatus =
addressResolver.getAddress({name: bytes32("SystemStatus")});

// deploy the account implementation
implementation = deployAccountImplementation({
implementation = new Account({
_factory: address(factory),
_events: address(events),
_marginAsset: marginAsset,
_futuresMarketManager: futuresMarketManager,
_systemStatus: systemStatus,
_gelato: _gelato,
_ops: _ops
_ops: _ops,
_settings: address(settings)
});

// update the factory with the new account implementation
Expand All @@ -58,64 +74,22 @@ contract Setup {
// transfer ownership of the factory to the owner
factory.transferOwnership({newOwner: _owner});
}

function deploySmartMarginFactory(address _owner)
internal
returns (Factory factory)
{
factory = new Factory({
_owner: _owner
});
}

function deployEvents(address _factory) internal returns (Events events) {
events = new Events({
_factory: _factory
});
}

function deployAccountImplementation(
address _factory,
address _events,
address _marginAsset,
address _futuresMarketManager,
address _systemStatus,
address _gelato,
address _ops
) internal returns (Account implementation) {
implementation = new Account({
_factory: _factory,
_events: _events,
_marginAsset: _marginAsset,
_futuresMarketManager: _futuresMarketManager,
_systemStatus: _systemStatus,
_gelato: _gelato,
_ops: _ops
});
}
}

/// @dev steps to deploy and verify on Optimism:
/// (1) load the variables in the .env file via `source .env`
/// (2) run `forge script script/Deploy.s.sol:DeployOptimism --rpc-url $ARCHIVE_NODE_URL_L2 --broadcast --verify -vvvv`
contract DeployOptimism is Script, Setup {
address private constant KWENTA_ADMIN_DAO_MULTI_SIG =
0xF510a2Ff7e9DD7e18629137adA4eb56B9c13E885;
address private constant SYNTHETIX_ADDRESS_RESOLVER =
0x1Cb059b7e74fD21665968C908806143E744D5F30;
address private constant GELATO = 0x01051113D81D7d6DA508462F2ad6d7fD96cF42Ef;
address private constant OPS = 0x340759c8346A1E6Ed92035FB8B6ec57cE1D82c2c;

function run() public {
uint256 deployerPrivateKey = vm.envUint("DEPLOYER_PRIVATE_KEY");
vm.startBroadcast(deployerPrivateKey);

Setup.deploySystem({
_deployer: 0x39CFcA7b389529ac861CbB05aDD802e5B06E5101,
_owner: KWENTA_ADMIN_DAO_MULTI_SIG,
_addressResolver: SYNTHETIX_ADDRESS_RESOLVER,
_gelato: GELATO,
_ops: OPS
_deployer: OPTIMISM_DEPLOYER,
_owner: OPTIMISM_KWENTA_ADMIN_DAO_MULTI_SIG,
_addressResolver: OPTIMISM_SYNTHETIX_ADDRESS_RESOLVER,
_gelato: OPTIMISM_GELATO,
_ops: OPTIMISM_OPS
});

vm.stopBroadcast();
Expand All @@ -125,25 +99,17 @@ contract DeployOptimism is Script, Setup {
/// @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/Deploy.s.sol:DeployOptimismGoerli --rpc-url $ARCHIVE_NODE_URL_GOERLI_L2 --broadcast --verify -vvvv`
/// @dev here the KWENTA_ADMIN_DAO_MULTI_SIG is the deployer address
contract DeployOptimismGoerli is Script, Setup {
address private constant KWENTA_ADMIN_DAO_MULTI_SIG =
0xc625F59d51ecDff57FEFE535C80d318CA42A0Ec4;
address private constant SYNTHETIX_ADDRESS_RESOLVER =
0x9Fc84992dF5496797784374B810E04238728743d;
address private constant GELATO = 0xF82D64357D9120a760e1E4C75f646C0618eFc2F3;
address private constant OPS = 0x255F82563b5973264e89526345EcEa766DB3baB2;

function run() public {
uint256 deployerPrivateKey = vm.envUint("DEPLOYER_PRIVATE_KEY");
vm.startBroadcast(deployerPrivateKey);

Setup.deploySystem({
_deployer: 0xc625F59d51ecDff57FEFE535C80d318CA42A0Ec4,
_owner: KWENTA_ADMIN_DAO_MULTI_SIG,
_addressResolver: SYNTHETIX_ADDRESS_RESOLVER,
_gelato: GELATO,
_ops: OPS
_deployer: OPTIMISM_GOERLI_DEPLOYER,
_owner: OPTIMISM_GOERLI_KWENTA_ADMIN_DAO_MULTI_SIG,
_addressResolver: OPTIMISM_GOERLI_SYNTHETIX_ADDRESS_RESOLVER,
_gelato: OPTIMISM_GOERLI_GELATO,
_ops: OPTIMISM_GOERLI_OPS
});

vm.stopBroadcast();
Expand Down
29 changes: 29 additions & 0 deletions script/utils/deploy-parameters.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.18;

/*//////////////////////////////////////////////////////////////
OPTIMISM
//////////////////////////////////////////////////////////////*/

address constant OPTIMISM_DEPLOYER = 0x39CFcA7b389529ac861CbB05aDD802e5B06E5101;
address constant OPTIMISM_KWENTA_ADMIN_DAO_MULTI_SIG =
0xF510a2Ff7e9DD7e18629137adA4eb56B9c13E885;
address constant OPTIMISM_SYNTHETIX_ADDRESS_RESOLVER =
0x1Cb059b7e74fD21665968C908806143E744D5F30;
address constant OPTIMISM_GELATO = 0x01051113D81D7d6DA508462F2ad6d7fD96cF42Ef;
address constant OPTIMISM_OPS = 0x340759c8346A1E6Ed92035FB8B6ec57cE1D82c2c;

/*//////////////////////////////////////////////////////////////
OPTIMISM GOERLI
//////////////////////////////////////////////////////////////*/

address constant OPTIMISM_GOERLI_DEPLOYER =
0xc625F59d51ecDff57FEFE535C80d318CA42A0Ec4;
address constant OPTIMISM_GOERLI_KWENTA_ADMIN_DAO_MULTI_SIG =
0xc625F59d51ecDff57FEFE535C80d318CA42A0Ec4;
address constant OPTIMISM_GOERLI_SYNTHETIX_ADDRESS_RESOLVER =
0x9Fc84992dF5496797784374B810E04238728743d;
address constant OPTIMISM_GOERLI_GELATO =
0xF82D64357D9120a760e1E4C75f646C0618eFc2F3;
address constant OPTIMISM_GOERLI_OPS =
0x255F82563b5973264e89526345EcEa766DB3baB2;
6 changes: 6 additions & 0 deletions script/utils/interfaces/IAddressResolver.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.18;

interface IAddressResolver {
function getAddress(bytes32 name) external view returns (address);
}
29 changes: 27 additions & 2 deletions src/Account.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
IFactory,
IFuturesMarketManager,
IPerpsV2MarketConsolidated,
ISettings,
ISystemStatus
} from "./interfaces/IAccount.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
Expand All @@ -22,7 +23,7 @@ contract Account is IAccount, Auth, OpsReady {
//////////////////////////////////////////////////////////////*/

/// @inheritdoc IAccount
bytes32 public constant VERSION = "2.0.0";
bytes32 public constant VERSION = "2.0.1";

/// @notice tracking code used when modifying positions
bytes32 internal constant TRACKING_CODE = "KWENTA";
Expand Down Expand Up @@ -53,6 +54,9 @@ contract Account is IAccount, Auth, OpsReady {
/// @dev the system status contract is used to check if the system is operational
ISystemStatus internal immutable SYSTEM_STATUS;

/// @notice address of contract used to store global settings
ISettings internal immutable SETTINGS;

/*//////////////////////////////////////////////////////////////
STATE
//////////////////////////////////////////////////////////////*/
Expand All @@ -66,6 +70,22 @@ contract Account is IAccount, Auth, OpsReady {
/// @notice track conditional orders by id
mapping(uint256 id => ConditionalOrder order) internal conditionalOrders;

/*//////////////////////////////////////////////////////////////
MODIFIERS
//////////////////////////////////////////////////////////////*/

modifier isAccountExecutionEnabled() {
_isAccountExecutionEnabled();

_;
}

function _isAccountExecutionEnabled() internal view {
if (!SETTINGS.accountExecutionEnabled()) {
revert AccountExecutionDisabled();
}
}

/*//////////////////////////////////////////////////////////////
CONSTRUCTOR
//////////////////////////////////////////////////////////////*/
Expand All @@ -78,20 +98,23 @@ contract Account is IAccount, Auth, OpsReady {
/// @param _futuresMarketManager: address of the Synthetix FuturesMarketManager
/// @param _gelato: address of Gelato
/// @param _ops: address of Ops
/// @param _settings: address of contract used to store global settings
constructor(
address _factory,
address _events,
address _marginAsset,
address _futuresMarketManager,
address _systemStatus,
address _gelato,
address _ops
address _ops,
address _settings
) Auth(address(0)) OpsReady(_gelato, _ops) {
FACTORY = IFactory(_factory);
EVENTS = IEvents(_events);
MARGIN_ASSET = IERC20(_marginAsset);
FUTURES_MARKET_MANAGER = IFuturesMarketManager(_futuresMarketManager);
SYSTEM_STATUS = ISystemStatus(_systemStatus);
SETTINGS = ISettings(_settings);
}

/*//////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -182,6 +205,7 @@ contract Account is IAccount, Auth, OpsReady {
external
payable
override
isAccountExecutionEnabled
{
uint256 numCommands = _commands.length;
if (_inputs.length != numCommands) {
Expand Down Expand Up @@ -716,6 +740,7 @@ contract Account is IAccount, Auth, OpsReady {
function executeConditionalOrder(uint256 _conditionalOrderId)
external
override
isAccountExecutionEnabled
onlyOps
{
ConditionalOrder memory conditionalOrder =
Expand Down
16 changes: 16 additions & 0 deletions src/Settings.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.18;

import {ISettings} from "./interfaces/ISettings.sol";
import {Owned} from "@solmate/auth/Owned.sol";

contract Settings is ISettings, Owned {
bool public accountExecutionEnabled = true;

constructor(address _owner) Owned(_owner) {}

function setAccountExecutionEnabled(bool _enabled) external onlyOwner {
accountExecutionEnabled = _enabled;
emit AccountExecutionEnabledSet(_enabled);
}
}
4 changes: 4 additions & 0 deletions src/interfaces/IAccount.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {IFactory} from "./IFactory.sol";
import {IFuturesMarketManager} from "@synthetix/IFuturesMarketManager.sol";
import {IPerpsV2MarketConsolidated} from
"@synthetix/IPerpsV2MarketConsolidated.sol";
import {ISettings} from "./ISettings.sol";
import {ISystemStatus} from "@synthetix/ISystemStatus.sol";

/// @title Kwenta Smart Margin Account Implementation Interface
Expand Down Expand Up @@ -102,6 +103,9 @@ interface IAccount {
/// 4. Price is zero
error InvalidPrice();

/// @notice thrown when account execution has been disabled in the settings contract
error AccountExecutionDisabled();

/*//////////////////////////////////////////////////////////////
VIEWS
//////////////////////////////////////////////////////////////*/
Expand Down
9 changes: 9 additions & 0 deletions src/interfaces/ISettings.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.18;

interface ISettings {
event AccountExecutionEnabledSet(bool enabled);

function accountExecutionEnabled() external view returns (bool);
function setAccountExecutionEnabled(bool _enabled) external;
}
Loading

0 comments on commit 71661a2

Please sign in to comment.