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

Mmarket #20

Open
wants to merge 14 commits into
base: settled-funds-remain-in-vault
Choose a base branch
from
12 changes: 12 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
[submodule "lib/forge-std"]
path = lib/forge-std
url = https://github.com/foundry-rs/forge-std
[submodule "mmarket/lib/forge-std"]
path = mmarket/lib/forge-std
url = https://github.com/foundry-rs/forge-std
[submodule "mmarket/lib/solmate"]
path = mmarket/lib/solmate
url = https://github.com/transmissions11/solmate
[submodule "mmarket/lib/openzeppelin-contracts-upgradeable"]
path = mmarket/lib/openzeppelin-contracts-upgradeable
url = https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable
[submodule "mmarket/lib/openzeppelin-contracts"]
path = mmarket/lib/openzeppelin-contracts
url = https://github.com/OpenZeppelin/openzeppelin-contracts
43 changes: 43 additions & 0 deletions mmarket/.github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
name: CI

on:
push:
pull_request:
workflow_dispatch:

env:
FOUNDRY_PROFILE: ci

jobs:
check:
strategy:
fail-fast: true

name: Foundry project
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: recursive

- name: Install Foundry
uses: foundry-rs/foundry-toolchain@v1

- name: Show Forge version
run: |
forge --version

- name: Run Forge fmt
run: |
forge fmt --check
id: fmt

- name: Run Forge build
run: |
forge build --sizes
id: build

- name: Run Forge tests
run: |
forge test -vvv
id: test
12 changes: 12 additions & 0 deletions mmarket/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Compiler files
cache/
out/

# Ignores development broadcast logs
/broadcast

# Docs
docs/

# Dotenv file
.env
66 changes: 66 additions & 0 deletions mmarket/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
## Foundry

**Foundry is a blazing fast, portable and modular toolkit for Ethereum application development written in Rust.**

Foundry consists of:

- **Forge**: Ethereum testing framework (like Truffle, Hardhat and DappTools).
- **Cast**: Swiss army knife for interacting with EVM smart contracts, sending transactions and getting chain data.
- **Anvil**: Local Ethereum node, akin to Ganache, Hardhat Network.
- **Chisel**: Fast, utilitarian, and verbose solidity REPL.

## Documentation

https://book.getfoundry.sh/

## Usage

### Build

```shell
$ forge build
```

### Test

```shell
$ forge test
```

### Format

```shell
$ forge fmt
```

### Gas Snapshots

```shell
$ forge snapshot
```

### Anvil

```shell
$ anvil
```

### Deploy

```shell
$ forge script script/Counter.s.sol:CounterScript --rpc-url <your_rpc_url> --private-key <your_private_key>
```

### Cast

```shell
$ cast <subcommand>
```

### Help

```shell
$ forge --help
$ anvil --help
$ cast --help
```
10 changes: 10 additions & 0 deletions mmarket/foundry.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[profile.default]
src = "src"
out = "out"
libs = ["lib"]

# See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options

[etherscan]
baseSepolia = { key = "${BASESCAN_API_KEY}", url = "https://api-sepolia.basescan.org/api", chain = 84532 }
baseMainnet = { key = "${BASESCAN_API_KEY}", url = "https://api.basescan.org/api", chain = 8453 }
1 change: 1 addition & 0 deletions mmarket/lib/forge-std
Submodule forge-std added at 3b20d6
1 change: 1 addition & 0 deletions mmarket/lib/openzeppelin-contracts
Submodule openzeppelin-contracts added at acd4ff
1 change: 1 addition & 0 deletions mmarket/lib/openzeppelin-contracts-upgradeable
1 change: 1 addition & 0 deletions mmarket/lib/solmate
Submodule solmate added at c93f77
35 changes: 35 additions & 0 deletions mmarket/script/MMarketTestnet.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.22;

import {Script} from 'forge-std/Script.sol';
import {StdCheats} from 'forge-std/StdCheats.sol';

import "lib/openzeppelin-contracts/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
import {MMarket} from 'src/MMarket.sol';
import 'forge-std/console.sol';

contract DeploymentScript is Script, StdCheats {
address deployer;

MMarket internal mmarket;
MMarket internal mmarketImpl;
TransparentUpgradeableProxy internal mmarketProxy;
ProxyAdmin internal mmarketProxyAdmin;

function run() public virtual {
uint256 deployerPrivateKey = vm.envUint('BASE_TESTNET_DEPLOYER_PRIVATE_KEY');

vm.startBroadcast(deployerPrivateKey);
deployer = vm.addr(deployerPrivateKey);

// mmarketImpl = new MMarket();
// mmarketProxy = new TransparentUpgradeableProxy(address(mmarketImpl), msg.sender, '');
// mmarketProxyAdmin = ProxyAdmin(address(uint160(uint256(vm.load(address(mmarketProxy), ERC1967Utils.ADMIN_SLOT)))));
// mmarket = MMarket(address(mmarketProxy));
// mmarket.initialize();
mmarket = MMarket(0xADe026d54D4BF35C585D671a76E23AFbaa010867);
mmarket.setOperator(0x34973347D332F97b57e5f0953Ad5864Ba8E579DD);
vm.stopBroadcast();
console.log('MMarket:', address(mmarket));
}
}
5 changes: 5 additions & 0 deletions mmarket/script/deployBaseTestnet.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/bin/bash
source .env
export BASESCAN_API_KEY=DYR5VWFHGC62MIJ9RZSX6V34N16H77B3QW
echo "guh"
forge script script/MMarketTestnet.s.sol:DeploymentScript --sig "run()" --fork-url https://base-sepolia.g.alchemy.com/v2/sPLbeK1fKZsqDemsivHO1d3AUlfZMBl- --broadcast -vv --sender 0x34973347D332F97b57e5f0953Ad5864Ba8E579DD --verify
5 changes: 5 additions & 0 deletions mmarket/script/deployMonadTestnet.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/bin/bash
source script/.env
export BASESCAN_API_KEY=DYR5VWFHGC62MIJ9RZSX6V34N16H77B3QW
echo "guh"
forge script script/MMarketTestnet.s.sol:DeploymentScript --sig "run()" --fork-url https://testnet-rpc2.monad.xyz/52227f026fa8fac9e2014c58fbf5643369b3bfc6 --broadcast -vv --sender 0x34973347D332F97b57e5f0953Ad5864Ba8E579DD --verify
159 changes: 159 additions & 0 deletions mmarket/src/MMarket.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
/**
* SPDX-License-Identifier: UNLICENSED
*/
pragma solidity ^0.8.22;

import './MMarketOperations.sol';

import 'lib/solmate/src/tokens/ERC20.sol';
import 'lib/solmate/src/utils/SafeTransferLib.sol';

import 'lib/openzeppelin-contracts/contracts/utils/cryptography/ECDSA.sol';
import 'lib/openzeppelin-contracts-upgradeable/contracts/access/OwnableUpgradeable.sol';
import 'lib/openzeppelin-contracts-upgradeable/contracts/utils/ReentrancyGuardUpgradeable.sol';
import 'lib/openzeppelin-contracts-upgradeable/contracts/utils/cryptography/EIP712Upgradeable.sol';

/**
* @author Jib
* @title MMarket
*/
contract MMarket is EIP712Upgradeable, OwnableUpgradeable, ReentrancyGuardUpgradeable {
/// @dev operator
address operator;
/// @dev mapping between user and an asset and the amount of the asset in the pool
mapping(address => mapping(address => uint256)) public userBalances;

/// @notice emits an event when MMarket receive funds from controller
event TransferToPool(address indexed asset, address indexed user, uint256 amount);
/// @notice emits an event when MMarket transfer funds to controller
event TransferToUser(address indexed asset, address indexed user, uint256 amount);
/// @notice emits an event when mmarket transfers funds between accounts
event InternalTransferIncrease(address indexed asset, address indexed user, uint256 amount);
/// @notice emits an event when mmarket transfers funds between accounts
event InternalTransferDecrease(address indexed asset, address indexed user, uint256 amount);
/// @notice emits an event when there is a change in operator
event OperatorChanged(address newOperator, address oldOperator);

function initialize() external initializer {
__EIP712_init('mmarket', '0.0.0');
__Ownable_init(msg.sender);
__ReentrancyGuard_init();
}

function setOperator(address _operator) external {
_checkOwner();
emit OperatorChanged(_operator, operator);
operator = _operator;
}

function _checkOperator() internal view virtual {
if (operator != _msgSender()) {
revert('bad operator');
}
}

function operate(MMarketOperations.Operation[] memory operations) external nonReentrant {
_checkOperator();

for (uint256 i = 0; i < operations.length; i++) {
MMarketOperations.Operation memory operation = operations[i];
MMarketOperations.OperationType operationType = operation.operationType;

if (operationType == MMarketOperations.OperationType.Deposit) {
deposit(MMarketOperations.parseDepositArgs(operation));
} else if (operationType == MMarketOperations.OperationType.Withdraw) {
withdraw(MMarketOperations.parseWithdrawArgs(operation));
} else if (operationType == MMarketOperations.OperationType.ConductTrade) {
conductTrade(MMarketOperations.parseConductTradeArgs(operation));
} else if (operationType == MMarketOperations.OperationType.Settle) {
settle(MMarketOperations.parseSettleArgs(operation));
}
}
}

function deposit(MMarketOperations.Operation memory _deposit) internal {
transferToPool(_deposit.asset_1, _deposit.user_1, _deposit.amount_1);
}

function withdraw(MMarketOperations.Operation memory _withdraw) internal {
transferToUser(_withdraw.asset_1, _withdraw.user_1, _withdraw.amount_1);
}

function conductTrade(MMarketOperations.Operation memory _conductTrade) internal {
transferBetweenUsers(
_conductTrade.asset_1,
_conductTrade.asset_2,
_conductTrade.user_1,
_conductTrade.user_2,
_conductTrade.amount_1,
_conductTrade.amount_2
);
transferToUser(_conductTrade.asset_1, _conductTrade.user_2, _conductTrade.amount_1);
}

function settle(MMarketOperations.Operation memory _settle) internal {}

/**
* @notice transfers an asset from a user to the pool
* @param _asset address of the asset to transfer
* @param _user address of the user to transfer assets from
* @param _amount amount of the token to transfer from _user
*/
function transferToPool(
address _asset,
address _user,
uint256 _amount
) internal {
require(_amount > 0, 'MMarket: transferToPool amount is equal to 0');

userBalances[_user][_asset] += _amount;

// transfer _asset _amount from _user to pool
SafeTransferLib.safeTransferFrom(ERC20(_asset), _user, address(this), _amount);
emit TransferToPool(_asset, _user, _amount);
}

/**
* @notice transfers an asset from the pool to a user
* @param _asset address of the asset to transfer
* @param _user address of the user to transfer assets to
* @param _amount amount of the token to transfer to _user
*/
function transferToUser(
address _asset,
address _user,
uint256 _amount
) internal {
require(_user != address(this), 'MMarket: cannot transfer assets to oneself');

userBalances[_user][_asset] -= _amount;

// transfer _asset _amount from pool to _user
SafeTransferLib.safeTransfer(ERC20(_asset), _user, _amount);
emit TransferToUser(_asset, _user, _amount);
}

// we transfer asset 1 and amount 1 to user 2 and asset 2 and amount 2 to user 1
function transferBetweenUsers(
address asset_1,
address asset_2,
address user_1,
address user_2,
uint256 amount_1,
uint256 amount_2
) internal {
require(user_1 != address(this), 'MMarket: user_1 cannot transfer assets to oneself');
require(user_2 != address(this), 'MMarket: user_2 cannot transfer assets to oneself');

userBalances[user_1][asset_1] -= amount_1;
userBalances[user_2][asset_1] += amount_1;

userBalances[user_1][asset_2] += amount_2;
userBalances[user_2][asset_2] -= amount_2;

emit InternalTransferIncrease(user_2, asset_1, amount_1);
emit InternalTransferIncrease(user_1, asset_2, amount_2);
emit InternalTransferDecrease(user_1, asset_1, amount_1);
emit InternalTransferDecrease(user_2, asset_2, amount_2);
}
}
Loading
Loading