-
Notifications
You must be signed in to change notification settings - Fork 239
/
ExchangeV2Core.sol
105 lines (90 loc) · 4.68 KB
/
ExchangeV2Core.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
// SPDX-License-Identifier: MIT
pragma solidity 0.7.6;
pragma abicoder v2;
import "./LibFill.sol";
import "./LibOrder.sol";
import "./OrderValidator.sol";
import "./AssetMatcher.sol";
import "./TransferExecutor.sol";
import "./ITransferManager.sol";
import "./lib/LibTransfer.sol";
abstract contract ExchangeV2Core is Initializable, OwnableUpgradeable, AssetMatcher, TransferExecutor, OrderValidator, ITransferManager {
using SafeMathUpgradeable for uint;
using LibTransfer for address;
uint256 private constant UINT256_MAX = 2 ** 256 - 1;
//state of the orders
mapping(bytes32 => uint) public fills;
//events
event Cancel(bytes32 hash, address maker, LibAsset.AssetType makeAssetType, LibAsset.AssetType takeAssetType);
event Match(bytes32 leftHash, bytes32 rightHash, address leftMaker, address rightMaker, uint newLeftFill, uint newRightFill, LibAsset.AssetType leftAsset, LibAsset.AssetType rightAsset);
function cancel(LibOrder.Order memory order) external {
require(_msgSender() == order.maker, "not a maker");
require(order.salt != 0, "0 salt can't be used");
bytes32 orderKeyHash = LibOrder.hashKey(order);
fills[orderKeyHash] = UINT256_MAX;
emit Cancel(orderKeyHash, order.maker, order.makeAsset.assetType, order.takeAsset.assetType);
}
function matchOrders(
LibOrder.Order memory orderLeft,
bytes memory signatureLeft,
LibOrder.Order memory orderRight,
bytes memory signatureRight
) external payable {
validateFull(orderLeft, signatureLeft);
validateFull(orderRight, signatureRight);
if (orderLeft.taker != address(0)) {
require(orderRight.maker == orderLeft.taker, "leftOrder.taker verification failed");
}
if (orderRight.taker != address(0)) {
require(orderRight.taker == orderLeft.maker, "rightOrder.taker verification failed");
}
matchAndTransfer(orderLeft, orderRight);
}
function matchAndTransfer(LibOrder.Order memory orderLeft, LibOrder.Order memory orderRight) internal {
(LibAsset.AssetType memory makeMatch, LibAsset.AssetType memory takeMatch) = matchAssets(orderLeft, orderRight);
bytes32 leftOrderKeyHash = LibOrder.hashKey(orderLeft);
bytes32 rightOrderKeyHash = LibOrder.hashKey(orderRight);
uint leftOrderFill = getOrderFill(orderLeft, leftOrderKeyHash);
uint rightOrderFill = getOrderFill(orderRight, rightOrderKeyHash);
LibFill.FillResult memory newFill = LibFill.fillOrder(orderLeft, orderRight, leftOrderFill, rightOrderFill);
require(newFill.takeValue > 0, "nothing to fill");
if (orderLeft.salt != 0) {
fills[leftOrderKeyHash] = leftOrderFill.add(newFill.takeValue);
}
if (orderRight.salt != 0) {
fills[rightOrderKeyHash] = rightOrderFill.add(newFill.makeValue);
}
(uint totalMakeValue, uint totalTakeValue) = doTransfers(makeMatch, takeMatch, newFill, orderLeft, orderRight);
if (makeMatch.assetClass == LibAsset.ETH_ASSET_CLASS) {
require(takeMatch.assetClass != LibAsset.ETH_ASSET_CLASS);
require(msg.value >= totalMakeValue, "not enough eth");
if (msg.value > totalMakeValue) {
address(msg.sender).transferEth(msg.value.sub(totalMakeValue));
}
} else if (takeMatch.assetClass == LibAsset.ETH_ASSET_CLASS) {
require(msg.value >= totalTakeValue, "not enough eth");
if (msg.value > totalTakeValue) {
address(msg.sender).transferEth(msg.value.sub(totalTakeValue));
}
}
emit Match(leftOrderKeyHash, rightOrderKeyHash, orderLeft.maker, orderRight.maker, newFill.takeValue, newFill.makeValue, makeMatch, takeMatch);
}
function getOrderFill(LibOrder.Order memory order, bytes32 hash) internal view returns (uint fill) {
if (order.salt == 0) {
fill = 0;
} else {
fill = fills[hash];
}
}
function matchAssets(LibOrder.Order memory orderLeft, LibOrder.Order memory orderRight) internal view returns (LibAsset.AssetType memory makeMatch, LibAsset.AssetType memory takeMatch) {
makeMatch = matchAssets(orderLeft.makeAsset.assetType, orderRight.takeAsset.assetType);
require(makeMatch.assetClass != 0, "assets don't match");
takeMatch = matchAssets(orderLeft.takeAsset.assetType, orderRight.makeAsset.assetType);
require(takeMatch.assetClass != 0, "assets don't match");
}
function validateFull(LibOrder.Order memory order, bytes memory signature) internal view {
LibOrder.validate(order);
validate(order, signature);
}
uint256[49] private __gap;
}