Skip to content

Commit

Permalink
Merge pull request #56 from sushiswap/fix/improved-exchange
Browse files Browse the repository at this point in the history
Improve BaseExchange and strategies
  • Loading branch information
levx-me committed Sep 29, 2021
2 parents 4734c1e + 22436e1 commit 3d84540
Show file tree
Hide file tree
Showing 62 changed files with 4,879 additions and 2,523 deletions.
68 changes: 0 additions & 68 deletions contracts/ExchangeProxy.sol

This file was deleted.

49 changes: 42 additions & 7 deletions contracts/base/BaseExchange.sol
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,11 @@ abstract contract BaseExchange is ReentrancyGuardInitializable, IBaseExchange {
uint256 price;
address recipient;
address referrer;
uint256 blockNumber;
uint256 timestamp;
}

mapping(address => mapping(bytes32 => mapping(address => bytes32))) internal _bidHashes;

mapping(bytes32 => BestBid) public override bestBid;
mapping(bytes32 => bool) public override isCancelledOrClaimed;
mapping(bytes32 => uint256) public override amountFilled;
Expand All @@ -42,6 +44,14 @@ abstract contract BaseExchange is ReentrancyGuardInitializable, IBaseExchange {
return token == address(this);
}

function approvedBidHash(
address proxy,
bytes32 askHash,
address bidder
) external view override returns (bytes32 bidHash) {
return _bidHashes[proxy][askHash][bidder];
}

function _transfer(
address token,
address from,
Expand All @@ -51,7 +61,7 @@ abstract contract BaseExchange is ReentrancyGuardInitializable, IBaseExchange {
) internal virtual;

function cancel(Orders.Ask memory order) external override {
require(order.signer == msg.sender, "SHOYU: FORBIDDEN");
require(order.signer == msg.sender || order.proxy == msg.sender, "SHOYU: FORBIDDEN");

bytes32 hash = order.hash();
require(bestBid[hash].bidder == address(0), "SHOYU: BID_EXISTS");
Expand All @@ -61,6 +71,15 @@ abstract contract BaseExchange is ReentrancyGuardInitializable, IBaseExchange {
emit Cancel(hash);
}

function updateApprovedBidHash(
bytes32 askHash,
address bidder,
bytes32 bidHash
) external override {
_bidHashes[msg.sender][askHash][bidder] = bidHash;
emit UpdateApprovedBidHash(msg.sender, askHash, bidder, bidHash);
}

function bid(Orders.Ask memory askOrder, Orders.Bid memory bidOrder)
external
override
Expand All @@ -71,7 +90,17 @@ abstract contract BaseExchange is ReentrancyGuardInitializable, IBaseExchange {
require(askHash == bidOrder.askHash, "SHOYU: UNMATCHED_HASH");
require(bidOrder.signer != address(0), "SHOYU: INVALID_SIGNER");

Signature.verify(bidOrder.hash(), bidOrder.signer, bidOrder.v, bidOrder.r, bidOrder.s, DOMAIN_SEPARATOR());
bytes32 bidHash = bidOrder.hash();
if (askOrder.proxy != address(0)) {
require(
askOrder.proxy == msg.sender || _bidHashes[askOrder.proxy][askHash][bidOrder.signer] == bidHash,
"SHOYU: FORBIDDEN"
);
delete _bidHashes[askOrder.proxy][askHash][bidOrder.signer];
emit UpdateApprovedBidHash(askOrder.proxy, askHash, bidOrder.signer, bytes32(0));
}

Signature.verify(bidHash, bidOrder.signer, bidOrder.v, bidOrder.r, bidOrder.s, DOMAIN_SEPARATOR());

return
_bid(
Expand All @@ -92,6 +121,8 @@ abstract contract BaseExchange is ReentrancyGuardInitializable, IBaseExchange {
address bidRecipient,
address bidReferrer
) external override nonReentrant returns (bool executed) {
require(askOrder.proxy == address(0), "SHOYU: FORBIDDEN");

return _bid(askOrder, askOrder.hash(), msg.sender, bidAmount, bidPrice, bidRecipient, bidReferrer);
}

Expand All @@ -115,16 +146,18 @@ abstract contract BaseExchange is ReentrancyGuardInitializable, IBaseExchange {
BestBid storage best = bestBid[askHash];
if (
IStrategy(askOrder.strategy).canClaim(
askOrder.proxy,
askOrder.deadline,
askOrder.params,
bidder,
bidPrice,
best.bidder,
best.price,
best.blockNumber
best.timestamp
)
) {
amountFilled[askHash] = _amountFilled + bidAmount;
if (_amountFilled + bidAmount == askOrder.amount) isCancelledOrClaimed[askHash] = true;

address recipient = askOrder.recipient;
if (recipient == address(0)) recipient = askOrder.signer;
Expand All @@ -148,21 +181,22 @@ abstract contract BaseExchange is ReentrancyGuardInitializable, IBaseExchange {
} else {
if (
IStrategy(askOrder.strategy).canBid(
askOrder.proxy,
askOrder.deadline,
askOrder.params,
bidder,
bidPrice,
best.bidder,
best.price,
best.blockNumber
best.timestamp
)
) {
best.bidder = bidder;
best.amount = bidAmount;
best.price = bidPrice;
best.recipient = bidRecipient;
best.referrer = bidReferrer;
best.blockNumber = block.number;
best.timestamp = block.timestamp;

emit Bid(askHash, bidder, bidAmount, bidPrice, bidRecipient, bidReferrer);
return false;
Expand All @@ -181,13 +215,14 @@ abstract contract BaseExchange is ReentrancyGuardInitializable, IBaseExchange {
BestBid memory best = bestBid[askHash];
require(
IStrategy(askOrder.strategy).canClaim(
askOrder.proxy,
askOrder.deadline,
askOrder.params,
best.bidder,
best.price,
best.bidder,
best.price,
best.blockNumber
best.timestamp
),
"SHOYU: FAILURE"
);
Expand Down
18 changes: 18 additions & 0 deletions contracts/interfaces/IBaseExchange.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ interface IBaseExchange {
address referrer
);
event Bid(bytes32 indexed hash, address bidder, uint256 amount, uint256 price, address recipient, address referrer);
event UpdateApprovedBidHash(
address indexed proxy,
bytes32 indexed askHash,
address indexed bidder,
bytes32 bidHash
);

function DOMAIN_SEPARATOR() external view returns (bytes32);

Expand All @@ -38,8 +44,20 @@ interface IBaseExchange {

function amountFilled(bytes32 hash) external view returns (uint256);

function approvedBidHash(
address proxy,
bytes32 askHash,
address bidder
) external view returns (bytes32 bidHash);

function cancel(Orders.Ask memory order) external;

function updateApprovedBidHash(
bytes32 askHash,
address bidder,
bytes32 bidHash
) external;

function bid(Orders.Ask memory askOrder, Orders.Bid memory bidOrder) external returns (bool executed);

function bid(
Expand Down
27 changes: 0 additions & 27 deletions contracts/interfaces/IExchangeProxy.sol

This file was deleted.

6 changes: 4 additions & 2 deletions contracts/interfaces/IStrategy.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,24 @@ import "../libraries/Orders.sol";

interface IStrategy {
function canClaim(
address proxy,
uint256 deadline,
bytes memory params,
address bidder,
uint256 bidPrice,
address bestBidder,
uint256 bestBidPrice,
uint256 bestBidBlock
uint256 bestBidTimestamp
) external view returns (bool);

function canBid(
address proxy,
uint256 deadline,
bytes memory params,
address bidder,
uint256 bidPrice,
address bestBidder,
uint256 bestBidPrice,
uint256 bestBidBlock
uint256 bestBidTimestamp
) external view returns (bool);
}
6 changes: 4 additions & 2 deletions contracts/libraries/Orders.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@
pragma solidity =0.8.3;

library Orders {
// keccak256("Ask(address signer,address token,uint256 tokenId,uint256 amount,address strategy,address currency,address recipient,uint256 deadline,bytes params)")
bytes32 internal constant ASK_TYPEHASH = 0x17fdf8831f8bd77353b30f42ba9bc64e7144545a42a890389f298feeb45dec88;
// keccak256("Ask(address signer,address proxy,address token,uint256 tokenId,uint256 amount,address strategy,address currency,address recipient,uint256 deadline,bytes params)")
bytes32 internal constant ASK_TYPEHASH = 0x5fbc9a24e1532fa5245d1ec2dc5592849ae97ac5475f361b1a1f7a6e2ac9b2fd;
// keccak256("Bid(bytes32 askHash,address signer,uint256 amount,uint256 price,address recipient,address referrer)")
bytes32 internal constant BID_TYPEHASH = 0xb98e1dc48988064e6dfb813618609d7da80a8841e5f277039788ac4b50d497b2;

struct Ask {
address signer;
address proxy;
address token;
uint256 tokenId;
uint256 amount;
Expand Down Expand Up @@ -41,6 +42,7 @@ library Orders {
abi.encode(
ASK_TYPEHASH,
ask.signer,
ask.proxy,
ask.token,
ask.tokenId,
ask.amount,
Expand Down
34 changes: 0 additions & 34 deletions contracts/strategies/DesignatedSale.sol

This file was deleted.

13 changes: 8 additions & 5 deletions contracts/strategies/DutchAuction.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import "../interfaces/IStrategy.sol";

contract DutchAuction is IStrategy {
function canClaim(
address proxy,
uint256 deadline,
bytes memory params,
address,
Expand All @@ -14,17 +15,19 @@ contract DutchAuction is IStrategy {
uint256,
uint256
) external view override returns (bool) {
(uint256 startPrice, uint256 endPrice, uint256 startBlock) = abi.decode(params, (uint256, uint256, uint256));
(uint256 startPrice, uint256 endPrice, uint256 startedAt) = abi.decode(params, (uint256, uint256, uint256));
require(startPrice > endPrice, "SHOYU: INVALID_PRICE_RANGE");
require(startBlock < deadline, "SHOYU: INVALID_START_BLOCK");
require(startedAt < deadline, "SHOYU: INVALID_STARTED_AT");

uint256 tickPerBlock = (startPrice - endPrice) / (deadline - startBlock);
uint256 currentPrice = startPrice - ((block.number - startBlock) * tickPerBlock);
uint256 tickPerBlock = (startPrice - endPrice) / (deadline - startedAt);
uint256 currentPrice =
block.timestamp >= deadline ? endPrice : startPrice - ((block.timestamp - startedAt) * tickPerBlock);

return block.number <= deadline && bidPrice >= currentPrice;
return (proxy != address(0) || block.timestamp <= deadline) && bidPrice >= currentPrice;
}

function canBid(
address,
uint256,
bytes memory,
address,
Expand Down
Loading

0 comments on commit 3d84540

Please sign in to comment.