forked from yehjxraymond/gmx-synthetics
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 298c6d7
Showing
87 changed files
with
29,331 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
root = true | ||
|
||
[*] | ||
indent_style = space | ||
indent_size = 2 | ||
end_of_line = lf | ||
charset = utf-8 | ||
trim_trailing_whitespace = true | ||
insert_final_newline = true | ||
|
||
[*.sol] | ||
indent_size = 4 | ||
|
||
[*.md] | ||
trim_trailing_whitespace = false |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
{ | ||
"env": { | ||
"browser": true, | ||
"commonjs": true, | ||
"es2021": true | ||
}, | ||
"overrides": [], | ||
"parserOptions": { | ||
"ecmaVersion": "latest" | ||
}, | ||
"extends": ["eslint:recommended"], | ||
"rules": {}, | ||
"globals": { | ||
"ethers": true, | ||
"describe": true, | ||
"it": true, | ||
"beforeEach": true | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
node_modules | ||
.env | ||
coverage | ||
coverage.json | ||
typechain | ||
typechain-types | ||
|
||
#Hardhat files | ||
cache | ||
artifacts | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
{ | ||
"semi": true, | ||
"singleQuote": false, | ||
"printWidth": 120 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
Business Source License 1.1 | ||
License text copyright (c) 2017 MariaDB Corporation Ab, All Rights Reserved. "Business Source License" is a trademark of MariaDB Corporation Ab. | ||
|
||
—---------------------------------------------------- | ||
|
||
Parameters | ||
Licensor: gmxresearch.eth | ||
Licensed Work: GMX Synthetics Contracts. The Licensed Work is (c) 2022 gmxresearch.eth | ||
Licensed Usage Grant: Uses listed and defined at synthetics-contracts-license-grants.gmxresearch.eth | ||
Change Date: The earlier of 31 August 2026 or a date specified at synthetics-contracts-license-date.gmxresearch.eth | ||
Change License: GNU General Public License v2.0 or later | ||
|
||
—------------------------------------------------------------------ | ||
|
||
Terms | ||
The Licensor hereby grants you the right to copy, modify, create derivative works, redistribute, and make non-production use of the Licensed Work. The Licensor may make an Additional Use Grant, above, permitting limited production use. | ||
Effective on the Change Date, or the fourth anniversary of the first publicly available distribution of a specific version of the Licensed Work under this License, whichever comes first, the Licensor hereby grants you rights under the terms of the Change License, and the rights granted in the paragraph above terminate. | ||
If your use of the Licensed Work does not comply with the requirements currently in effect as described in this License, you must purchase a commercial license from the Licensor, its affiliated entities, or authorized resellers, or you must refrain from using the Licensed Work. | ||
All copies of the original and modified Licensed Work, and derivative works of the Licensed Work, are subject to this License. This License applies separately for each version of the Licensed Work and the Change Date may vary for each version of the Licensed Work released by Licensor. | ||
You must conspicuously display this License on each original or modified copy of the Licensed Work. If you receive the Licensed Work in original or modified form from a third party, the terms and conditions set forth in this License apply to your use of that work. | ||
Any use of the Licensed Work in violation of this License will automatically terminate your rights under this License for the current and all other versions of the Licensed Work. | ||
This License does not grant you any right in any trademark or logo of Licensor or its affiliates (provided that you may use a trademark or logo of Licensor as expressly required by this License). | ||
TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND TITLE. | ||
MariaDB hereby grants you permission to use this License’s text to license your works, and to refer to it using the trademark "Business Source License", as long as you comply with the Covenants of Licensor below. | ||
|
||
—----------------------------------------------------------- | ||
|
||
Covenants of Licensor | ||
In consideration of the right to use this License’s text and the "Business Source License" name and trademark, Licensor covenants to MariaDB, and to all other recipients of the licensed work to be provided by Licensor: | ||
To specify as the Change License the GPL Version 2.0 or any later version, or a license that is compatible with GPL Version 2.0 or a later version, where "compatible" means that software provided under the Change License can be included in a program with software provided under GPL Version 2.0 or a later version. Licensor may specify additional Change Licenses without limitation. | ||
To either: (a) specify an additional grant of rights to use that does not impose any additional restriction on the right granted in this License, as the Additional Use Grant; or (b) insert the text "None". | ||
To specify a Change Date. | ||
Not to modify this License in any other way. | ||
|
||
—------------------------------------------- | ||
|
||
Notice | ||
The Business Source License (this document, or the "License") is not an Open Source license. However, the Licensed Work will eventually be made available under an Open Source License, as stated in this License. | ||
|
||
The Licensor does not own or run any deployments of the Licensed Work. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
# GMX Synthetics | ||
|
||
Contracts for GMX Synthetics. | ||
|
||
# Overview | ||
|
||
The contracts outline a system for swaps and perp trading. | ||
|
||
Markets are created with a long collateral token, short collateral token and index token. | ||
|
||
Examples: | ||
|
||
- ETH/USD market with long collateral as ETH, short collateral as a stablecoin, index token as ETH | ||
- BTC/USD market with long collateral as WBTC, short collateral as a stablecoin, index token as BTC | ||
- SOL/USD market with long collateral as ETH, short collateral as a stablecoin, index token as SOL | ||
|
||
Liquidity providers can deposit either the long or short collateral token to mint liquidity tokens. | ||
|
||
The long collateral token is used to back long positions, while the short collateral token is used to back short positions. | ||
|
||
Liquidity providers take on the profits and losses of traders for the market that they provide liquidity for. | ||
|
||
Having separate markets allows for risk isolation, liquidity providers are only exposed to the markets that they deposit into. | ||
|
||
The contracts potentially allow for permissionless listings. | ||
|
||
# Features | ||
|
||
The contracts support the following main features: | ||
|
||
- Deposit and withdrawal of liquidity | ||
- Spot Trading (Swaps) | ||
- Leverage Trading (Perps, Long / Short) | ||
- Market orders, limit orders, stop-loss, take-profit orders | ||
|
||
# Oracle System | ||
|
||
To avoid front-running issues, most actions require two steps to execute: | ||
|
||
- User sends transaction with request details, e.g. deposit / withdraw liquidity, swap, increase / decrease position | ||
- Keepers listen for the transactions, include the prices for the request then send a transaction to execute the request | ||
|
||
Prices are provided by an off-chain oracle system: | ||
|
||
- Oracle keepers continually check the latest blocks | ||
- When there is a new block, oracle keepers fetch the latest prices from reference exchanges | ||
- Oracle keepers then sign the median price for each token together with the block hash | ||
- Oracle keepers then send the data and signature to archive nodes | ||
- Archive nodes display this information for anyone to query | ||
|
||
Example: | ||
|
||
- Block 100 is finalized on the blockchain | ||
- Oracle keepers observe this block | ||
- Oracle keepers pull the latest prices from reference exchanges, token A: price 20,000, token B: price 80,000 | ||
- Oracle keepers sign [chainId, blockhash(100), 20,000], [chainId, blockhash(100), 80,000] | ||
- If in block 100, there was a market order to open a long position for token A, the market order would have a block number of 100 | ||
- The prices signed at block 100 can be used to execute this order | ||
- Order keepers would bundle the signature and price data for token A then execute the order | ||
|
||
# Fees and Pricing | ||
|
||
Funding fees and price impact keep longs / shorts balanced while reducing the risk of price manipulation. | ||
|
||
- Funding fees: if there is an imbalance of longs / shorts, the larger side pays a funding fee to the smaller side | ||
- Borrowing fees: to avoid a user opening equal longs / shorts and unnecessarily taking up capacity | ||
- Price impact: this allows the contracts to simulate a price impact similar to if the trader were trading using an aggregator for the reference exchanges, there is a negative price impact if an action reduces balance, and a positive price impact if an action improves balance | ||
|
||
# Keepers | ||
|
||
There are a few keepers and nodes in the system: | ||
|
||
- Oracle keepers: checks for latest finalized blocks, pull prices from reference exchanges, sign the information and publish it to Archive nodes | ||
- Archive nodes: receives oracle keeper signatures and allows querying of this information | ||
- Order keepers: checks for deposit / withdraw liquidity requests, order requests, bundles the signed oracle prices with the requests and executes them | ||
|
||
# Structure | ||
|
||
There are two main types of contracts: | ||
|
||
- Storage contracts which hold funds and have internal state | ||
- Logic contracts which do not hold funds and do not have internal state | ||
|
||
The contracts are separated into these two types to allow for gradual upgradeability. | ||
|
||
Using the OrderStore, OrderUtils and OrderHandler contracts as an example | ||
|
||
- OrderStore: stores orders and funds for orders | ||
- OrderUtils: logic library | ||
- OrderHandler: logic contract | ||
|
||
To avoid exceeding the maximum allowed contract size for contracts such as OrderHandler, OrderUtils and other library contracts are used. | ||
|
||
If order logic needs to be updated, a new OrderHandler can be created and can run alongside the existing OrderHandler until it is fully tested, this facilitates zero downtimes updates. | ||
|
||
Store contracts such as OrderStore, PositionStore store specific structs, while DataStore stores general data required by the system. | ||
|
||
EnumberableSets are used to allow order lists and position lists to be easily queried by interfaces or keepers, this is used over indexers as there may be a lag for indexers to sync the latest block. Having the lists stored directly in the contract also helps to ensure that accurate data can be retrieved and verified when needed. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
// SPDX-License-Identifier: BUSL-1.1 | ||
|
||
pragma solidity ^0.8.0; | ||
|
||
import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; | ||
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; | ||
|
||
import "../role/RoleModule.sol"; | ||
import "../eth/IWETH.sol"; | ||
|
||
contract Bank is RoleModule { | ||
using SafeERC20 for IERC20; | ||
|
||
constructor(RoleStore _roleStore) RoleModule(_roleStore) {} | ||
|
||
function transferOut(address token, uint256 amount, address receiver) external onlyController { | ||
_transferOut(token, amount, receiver); | ||
} | ||
|
||
function transferOut( | ||
address weth, | ||
address token, | ||
uint256 amount, | ||
address receiver, | ||
bool hasCollateralInETH | ||
) external onlyController { | ||
if (token == weth && hasCollateralInETH) { | ||
_transferOutEth(token, amount, receiver); | ||
} else { | ||
_transferOut(token, amount, receiver); | ||
} | ||
} | ||
|
||
function _transferOut(address token, uint256 amount, address receiver) internal { | ||
require(receiver != address(this), "Bank: invalid receiver"); | ||
|
||
IERC20(token).safeTransfer(receiver, amount); | ||
|
||
_afterTransferOut(token); | ||
} | ||
|
||
function _transferOutEth(address token, uint256 amount, address receiver) internal { | ||
require(receiver != address(this), "Bank: invalid receiver"); | ||
|
||
IWETH(token).withdraw(amount); | ||
payable(receiver).transfer(amount); | ||
|
||
_afterTransferOut(token); | ||
} | ||
|
||
function _afterTransferOut(address /* token */) internal virtual {} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
// SPDX-License-Identifier: BUSL-1.1 | ||
|
||
pragma solidity ^0.8.0; | ||
|
||
import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; | ||
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; | ||
|
||
import "../eth/IWETH.sol"; | ||
import "./Bank.sol"; | ||
|
||
contract StrictBank is Bank { | ||
using SafeERC20 for IERC20; | ||
|
||
// used to record token balances to evaluate amounts transferred in | ||
mapping (address => uint256) public tokenBalances; | ||
|
||
constructor(RoleStore _roleStore) Bank(_roleStore) {} | ||
|
||
function recordTransferIn(address token) external onlyController returns (uint256) { | ||
return _recordTransferIn(token); | ||
} | ||
|
||
function _recordTransferIn(address token) internal returns (uint256) { | ||
uint256 prevBalance = tokenBalances[token]; | ||
uint256 nextBalance = IERC20(token).balanceOf(address(this)); | ||
tokenBalances[token] = nextBalance; | ||
|
||
return nextBalance - prevBalance; | ||
} | ||
|
||
function _afterTransferOut(address token) internal override { | ||
tokenBalances[token] = IERC20(token).balanceOf(address(this)); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
// SPDX-License-Identifier: BUSL-1.1 | ||
|
||
pragma solidity ^0.8.0; | ||
|
||
import "../role/RoleModule.sol"; | ||
|
||
contract DataStore is RoleModule { | ||
mapping(bytes32 => uint256) public uintValues; | ||
mapping(bytes32 => int256) public intValues; | ||
mapping(bytes32 => address) public addressValues; | ||
mapping(bytes32 => bytes32) public dataValues; | ||
mapping(bytes32 => bool) public boolValues; | ||
|
||
constructor(RoleStore _roleStore) RoleModule(_roleStore) {} | ||
|
||
function getUint(bytes32 key) external view returns (uint256) { | ||
return uintValues[key]; | ||
} | ||
|
||
function setUint(bytes32 key, uint256 value) external onlyController returns (uint256) { | ||
uintValues[key] = value; | ||
return value; | ||
} | ||
|
||
function incrementUint(bytes32 key, uint256 value) external onlyController returns (uint256) { | ||
uint256 nextUint = uintValues[key] + value; | ||
uintValues[key] = nextUint; | ||
return nextUint; | ||
} | ||
|
||
function decrementUint(bytes32 key, uint256 value) external onlyController returns (uint256) { | ||
uint256 nextUint = uintValues[key] - value; | ||
uintValues[key] = nextUint; | ||
return nextUint; | ||
} | ||
|
||
function getInt(bytes32 key) external view returns (int256) { | ||
return intValues[key]; | ||
} | ||
|
||
function setInt(bytes32 key, int256 value) external onlyController returns (int256) { | ||
intValues[key] = value; | ||
return value; | ||
} | ||
|
||
function incrementInt(bytes32 key, int256 value) external onlyController returns (int256) { | ||
int256 nextInt = intValues[key] + value; | ||
intValues[key] = nextInt; | ||
return nextInt; | ||
} | ||
|
||
function decrementUint(bytes32 key, int256 value) external onlyController returns (int256) { | ||
int256 nextInt = intValues[key] - value; | ||
intValues[key] = nextInt; | ||
return nextInt; | ||
} | ||
|
||
function getAddress(bytes32 key) external view returns (address) { | ||
return addressValues[key]; | ||
} | ||
|
||
function setAddress(bytes32 key, address value) external onlyController returns (address) { | ||
addressValues[key] = value; | ||
return value; | ||
} | ||
|
||
function getData(bytes32 key) external view returns (bytes32) { | ||
return dataValues[key]; | ||
} | ||
|
||
function setData(bytes32 key, bytes32 value) external onlyController returns (bytes32) { | ||
dataValues[key] = value; | ||
return value; | ||
} | ||
|
||
function getBool(bytes32 key) external view returns (bool) { | ||
return boolValues[key]; | ||
} | ||
|
||
function setBool(bytes32 key, bool value) external onlyController returns (bool) { | ||
boolValues[key] = value; | ||
return value; | ||
} | ||
} |
Oops, something went wrong.