Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

clean(remove-contracts): removes prototype contract and related tests #2

Merged
merged 18 commits into from
May 15, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
b4cc465
clean(remove-contracts): removes prototype contract and related tests
Alexangelj May 14, 2022
efe7e95
test(enigma): adds ts and sol tests for enigma
Alexangelj May 14, 2022
059c2e2
test(HyperSwap): adds tests for hyper swap
Alexangelj May 14, 2022
fe46f33
test(liquidity): adds most tests for liquidity
Alexangelj May 14, 2022
3a48f8d
test(liquidity): finishes all liquidity tests
Alexangelj May 14, 2022
e66601a
test(compiler): adds test for settling balances and tokens
Alexangelj May 15, 2022
2c1ff87
fix(test-events): separates log event unit tests
Alexangelj May 15, 2022
8e2edae
test(process): adds tests for process function
Alexangelj May 15, 2022
75d5cb7
test(jump-process): adds jump process test in external compiler
Alexangelj May 15, 2022
4f2f713
test(all): all tests running after fixes
Alexangelj May 15, 2022
85c567d
docs(natspec-errors): adds natspec to enigma interfaces
Alexangelj May 15, 2022
96422ea
docs(interface-natspec): adds remaining natspec to interfaces
Alexangelj May 15, 2022
eecdeb4
clean(libraries): updates imports of libraries to audited rmm libs
Alexangelj May 15, 2022
ffd32fb
clean(remove-files): removes libraries and imports from rmm package
Alexangelj May 15, 2022
ff57e87
fix(create-pair): updates conditional checks in create pair
Alexangelj May 15, 2022
239b190
refactor(encoding-swap): updates encoding and swaps
Alexangelj May 15, 2022
cdcd5d9
feat(solmate): adds solmate safe transfer lib
Alexangelj May 15, 2022
6c7bb1f
finalize(pragma): locks pragma and final cleanup
Alexangelj May 15, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# Primitive Hyper

Function arguments bad, packed hex calldata good
Function arguments bad, packed hex calldata good.

> Note: outdated.

## Operations

Expand Down
69 changes: 37 additions & 32 deletions contracts/Compiler.sol
Original file line number Diff line number Diff line change
@@ -1,63 +1,63 @@
pragma solidity ^0.8.0;
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.10;

import "@rari-capital/solmate/src/utils/SafeTransferLib.sol";
import "@rari-capital/solmate/src/tokens/ERC20.sol";

import "./HyperSwap.sol";
import "./HyperLiquidity.sol";
import "./HyperSwap.sol";

/// @title Enigma Compiler
/// @notice Main contract of the Enigma that implements instruction processing.
/// @dev Eliminates the majority use of function signatures. Expects encoded bytes as msg.data in the fallback.
/// @dev Eliminates the use of function signatures. Expects encoded bytes as msg.data in the fallback.
contract Compiler is HyperLiquidity, HyperSwap {
// --- Fallback --- //

/// @notice Main touchpoint for receiving calls.
/// @dev Critical: data must be encoded properly to be processed.
/// @custom:security Critical. Guarded against re-entrancy. This is like the bank vault door.
/// @custom:mev Higher level security checks must be implemented by calling contract.
fallback() external payable lock {
if (msg.data[0] != INSTRUCTION_JUMP) {
_process(msg.data);
} else {
_jumpProcess(msg.data);
}

if (msg.data[0] != INSTRUCTION_JUMP) _process(msg.data);
else _jumpProcess(msg.data);
_settleBalances();
}

// --- Private --- //

/// @dev Critical array, used in jump process to track the pairs that were interacted with.
/// @notice Cleared at end, never permanently set.
uint16[] private _tempPairIds;
/// @notice Cleared at end and never permanently set.
/// @custom:security High. Without pairIds to loop through, no token amounts are settled.
uint16[] internal _tempPairIds;

/// @dev Flag set to true during `_process`. Set to false during `_settleToken`.
/// @dev Flag set to `true` during `_process`. Set to `false` during `_settleToken`.
/// @custom:security High. Referenced in settlement to pay for tokens due.
function _cacheAddress(address token, bool flag) private {
function _cacheAddress(address token, bool flag) internal {
addressCache[token] = flag;
}

// --- Internal --- //

/// @dev A non-zero credit is a receivalble paid to the `msg.sender` account.
/// @dev A positive credit is a receivable paid to the `msg.sender` internal balance.
/// Positive credits are only applied to the internal balance of the account.
/// Therefore, it does not require a state change for the global reserves.
/// @custom:security Critical. The only method that accounts are credited for tokens.
function _applyCredit(address token, uint256 amount) private {
/// @custom:security Critical. Only method which credits accounts with tokens.
function _applyCredit(address token, uint256 amount) internal {
balances[msg.sender][token] += amount;
emit Credit(token, amount);
}

/// @dev A non-zero debit is a cost that must be paid for a transaction to go through.
/// If a balance exists for the token for the respective account `msg.sender`,
/// @dev Dangerous! Calls to external contract with an inline assembly `safeTransferFrom`.
/// A positive debit is a cost that must be paid for a transaction to be processed.
/// If a balance exists for the token for the internal balance of `msg.sender`,
/// it will be used to pay the debit.
/// Else, tokens are expected to be transferred into this contract.
/// Else, tokens are expected to be transferred into this contract using `transferFrom`.
/// Externally paid debits increase the balance of the contract, so the global
/// reserves must be increased.
/// @custom:security Critical. Handles the payment of tokens for all pool actions.
function _applyDebit(address token, uint256 amount) private {
function _applyDebit(address token, uint256 amount) internal {
if (balances[msg.sender][token] >= amount) balances[msg.sender][token] -= amount;
else {
_increaseGlobal(token, amount);
IERC20(token).transferFrom(msg.sender, address(this), amount);
}
else SafeTransferLib.safeTransferFrom(ERC20(token), msg.sender, address(this), amount);
emit Debit(token, amount);
}

Expand All @@ -67,7 +67,7 @@ contract Compiler is HyperLiquidity, HyperSwap {
/// @custom:security Critical. Processes multiple instructions. Data must be encoded perfectly.
function _jumpProcess(bytes calldata data) internal {
uint8 length = uint8(data[1]);
uint8 pointer = 2; // note: [opcode, length, pointer, ...instruction, pointer, ...etc]
uint8 pointer = JUMP_PROCESS_START_POINTER; // note: [opcode, length, pointer, ...instruction, pointer, ...etc]
uint256 start;

// For each instruction set...
Expand All @@ -94,19 +94,22 @@ contract Compiler is HyperLiquidity, HyperSwap {
function _process(bytes calldata data) internal returns (uint16 pairId) {
uint48 poolId;
bytes1 instruction = bytes1(data[0] & 0x0f);
if (instruction == UNKNOWN) revert UnknownInstruction();

if (instruction == ADD_LIQUIDITY) {
(poolId, ) = _addLiquidity(data);
} else if (instruction == REMOVE_LIQUIDITY) {
(poolId, , ) = _removeLiquidity(data);
} else if (instruction == SWAP_EXACT_TOKENS_FOR_TOKENS) {
(poolId, ) = _swapExactTokens(data);
} else if (instruction == SWAP) {
(poolId, ) = _swapExactForExact(data);
} else if (instruction == CREATE_POOL) {
_createPool(data);
} else if (instruction == CREATE_CURVE) {
_createCurve(data);
} else if (instruction == CREATE_PAIR) {
_createPair(data);
} else {
revert UnknownInstruction();
}

// note: Only pool interactions have a non-zero poolId.
Expand All @@ -125,7 +128,7 @@ contract Compiler is HyperLiquidity, HyperSwap {
/// @custom:security Critical. Handles token payments with `_settleToken`.
function _settleBalances() internal {
uint256 len = _tempPairIds.length;
uint16[] memory ids = new uint16[](len);
uint16[] memory ids = _tempPairIds;
if (len == 0) return; // note: Dangerous! If pools were interacted with, this return being trigerred would be a failure.
for (uint256 i; i != len; ++i) {
uint16 pairId = ids[i];
Expand All @@ -140,11 +143,11 @@ contract Compiler is HyperLiquidity, HyperSwap {
/// @dev Increases the `msg.sender` internal balance of a token, or requests payment from them.
/// @param token Target token to pay or credit.
/// @custom:security Critical. Handles crediting accounts or requesting payment for debits.
function _settleToken(address token) private {
function _settleToken(address token) internal {
if (!addressCache[token]) return; // note: Early short circuit, since attempting to settle twice is common for big orders.

uint256 global = globalReserves[token];
uint256 actual = _balanceOf(token);
uint256 actual = _balanceOf(token, address(this));

if (global > actual) {
uint256 deficit = global - actual;
Expand All @@ -165,13 +168,15 @@ contract Compiler is HyperLiquidity, HyperSwap {
uint256 amount,
address to
) external lock {
// note: Would pull tokens without this conditional check.
if (balances[msg.sender][token] < amount) revert DrawBalance();
_applyDebit(token, amount);
IERC20(token).transfer(to, amount);
SafeTransferLib.safeTransfer(ERC20(token), to, amount);
}

/// @inheritdoc IEnigmaActions
function fund(address token, uint256 amount) external override lock {
_applyCredit(token, amount);
IERC20(token).transferFrom(msg.sender, address(this), amount);
SafeTransferLib.safeTransferFrom(ERC20(token), msg.sender, address(this), amount);
}
}
25 changes: 14 additions & 11 deletions contracts/EnigmaVirtualMachine.sol
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
pragma solidity ^0.8.0;
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.10;

import "./interfaces/IEnigma.sol";
import "./interfaces/IERC20.sol";
Expand All @@ -20,9 +21,9 @@ abstract contract EnigmaVirtualMachine is IEnigma {

// --- Internal --- //
/// @dev Gas optimized `balanceOf` method.
function _balanceOf(address token) internal view returns (uint256) {
function _balanceOf(address token, address account) internal view returns (uint256) {
(bool success, bytes memory data) = token.staticcall(
abi.encodeWithSelector(IERC20.balanceOf.selector, address(this))
abi.encodeWithSelector(IERC20.balanceOf.selector, account)
);
if (!success || data.length != 32) revert BalanceError();
return abi.decode(data, (uint256));
Expand All @@ -33,18 +34,16 @@ abstract contract EnigmaVirtualMachine is IEnigma {
return uint128(block.timestamp);
}

/// @dev Overridable in tests.
function _liquidityPolicy() internal view virtual returns (uint256) {
return JUST_IN_TIME_LIQUIDITY_POLICY;
}

// --- Instructions --- //
bytes1 public constant UNKNOWN = 0x00;
bytes1 public constant ADD_LIQUIDITY = 0x01;
bytes1 public constant ADD_LIQUIDITY_ETH = 0x02;
bytes1 public constant REMOVE_LIQUIDITY = 0x03;
bytes1 public constant REMOVE_LIQUIDITY_ETH = 0x04;
bytes1 public constant SWAP_EXACT_TOKENS_FOR_TOKENS = 0x05;
bytes1 public constant SWAP_TOKENS_FOR_EXACT_TOKENS = 0x06;
bytes1 public constant SWAP_EXACT_ETH_FOR_TOKENS = 0x07;
bytes1 public constant SWAP_TOKENS_FOR_EXACT_ETH = 0x08;
bytes1 public constant SWAP_EXACT_TOKENS_FOR_ETH = 0x09;
bytes1 public constant SWAP_ETH_FOR_EXACT_TOKENS = 0x0A;
bytes1 public constant SWAP = 0x05;
bytes1 public constant CREATE_POOL = 0x0B;
bytes1 public constant CREATE_PAIR = 0x0C;
bytes1 public constant CREATE_CURVE = 0x0D;
Expand Down Expand Up @@ -84,4 +83,8 @@ abstract contract EnigmaVirtualMachine is IEnigma {
uint256 public constant MAX_POOL_FEE = 1e3;
/// @dev Used to compute the amount of liquidity to burn on creating a pool.
uint256 public constant MIN_LIQUIDITY_FACTOR = 6;
/// @dev Policy for the "wait" time in seconds between adding and removing liquidity.
uint256 public constant JUST_IN_TIME_LIQUIDITY_POLICY = 4;
/// @dev Used as the first pointer for the jump process.
uint8 public constant JUMP_PROCESS_START_POINTER = 2;
}
Loading