Skip to content

Commit 5b36f4e

Browse files
committed
wip: polyswap contract v0.1
1 parent fdf47d8 commit 5b36f4e

File tree

3 files changed

+144
-4
lines changed

3 files changed

+144
-4
lines changed

remappings.txt

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,22 @@
11
@openzeppelin/=lib/composable-cow/lib/@openzeppelin/
2+
common/=lib/ctf-exchange/src/common/
23
composable-cow/=lib/composable-cow/
4+
@composable-cow/=lib/composable-cow/src
35
cowprotocol/=lib/composable-cow/lib/cowprotocol/src/
6+
creator/=lib/ctf-exchange/src/creator/
7+
ctf-exchange/=lib/ctf-exchange/src/
8+
dev/=lib/ctf-exchange/src/dev/
49
ds-test/=lib/composable-cow/lib/forge-std/lib/ds-test/src/
510
erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/
11+
exchange/=lib/ctf-exchange/src/exchange/
612
forge-std/=lib/forge-std/src/
13+
gov/=lib/ctf-exchange/src/gov/
714
halmos-cheatcodes/=lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/
15+
mocks/=lib/ctf-exchange/src/dev/mocks/
816
murky/=lib/composable-cow/lib/murky/src/
9-
openzeppelin-contracts/=lib/openzeppelin-contracts/
17+
openzeppelin-contracts/=lib/openzeppelin-contracts/contracts/
1018
openzeppelin/=lib/composable-cow/lib/@openzeppelin/contracts/
11-
safe/=lib/composable-cow/lib/safe/
19+
pool/=lib/ctf-exchange/src/dev/uniswap/
20+
ptoken/=lib/ctf-exchange/src/ptoken/
21+
safe/=lib/composable-cow/lib/safe/contracts/
22+
solmate/=lib/ctf-exchange/lib/solmate/src/

src/Polyswap.sol

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,45 @@
11
// SPDX-License-Identifier: UNLICENSED
22
pragma solidity >=0.8.0 <0.9.0;
33

4-
contract Polyswap {
5-
4+
import {
5+
IConditionalOrder,
6+
IConditionalOrderGenerator,
7+
GPv2Order,
8+
BaseConditionalOrder
9+
} from "@composable-cow/BaseConditionalOrder.sol";
10+
import {ComposableCoW} from "@composable-cow/ComposableCoW.sol";
11+
12+
import {Trading} from "exchange/mixins/Trading.sol";
13+
14+
import {PolyswapOrder} from "./PolyswapOrder.sol";
15+
16+
contract Polyswap is BaseConditionalOrder {
17+
ComposableCoW public immutable composableCow;
18+
Trading public immutable polymarket;
19+
20+
constructor(ComposableCoW _composableCow, Trading _polymarket) {
21+
composableCow = _composableCow;
22+
polymarket = _polymarket;
23+
}
24+
25+
/**
26+
* @inheritdoc IConditionalOrderGenerator
27+
* @dev `owner`, `sender`, 'ctx' and `offchainInput` is not used.
28+
*/
29+
function getTradeableOrder(address, address, bytes32, bytes calldata staticInput, bytes calldata)
30+
public
31+
view
32+
override
33+
returns (GPv2Order.Data memory order)
34+
{
35+
/**
36+
* @dev Decode the payload into a Polyswap bundle and get the order. `orderFor` will revert if it is not
37+
* currently a valid order.
38+
*/
39+
PolyswapOrder.Data memory polyswapOrder = abi.decode(staticInput, (PolyswapOrder.Data));
40+
41+
order = PolyswapOrder.orderFor(polyswapOrder, polymarket);
42+
43+
// check if the polymarket order is fulfilled
44+
}
645
}

src/PolyswapOrder.sol

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
// SPDX-License-Identifier: GPL-3.0
2+
pragma solidity >=0.8.0 <0.9.0;
3+
4+
import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol";
5+
import {IERC20, GPv2Order} from "cowprotocol/contracts/libraries/GPv2Order.sol";
6+
7+
import {IConditionalOrder} from "@composable-cow/interfaces/IConditionalOrder.sol";
8+
9+
import {Trading} from "exchange/mixins/Trading.sol";
10+
import {OrderStatus} from "exchange/libraries/OrderStructs.sol";
11+
12+
// --- error strings
13+
14+
string constant INVALID_SAME_TOKEN = "same token";
15+
string constant INVALID_TOKEN = "invalid token";
16+
string constant INVALID_SELL_AMOUNT = "invalid sell amount";
17+
string constant INVALID_MIN_BUY_AMOUNT = "invalid min buy amount";
18+
string constant INVALID_POLYMARKET_ORDER_HASH = "invalid order hash";
19+
string constant INVALID_START_DATE = "invalid start date";
20+
string constant INVALID_END_DATE = "invalid end date";
21+
22+
/**
23+
* @title Polyswap Order Library
24+
* @dev Structs, errors, and functions for Polyswap orders.
25+
*/
26+
library PolyswapOrder {
27+
using SafeCast for uint256;
28+
29+
// --- structs
30+
31+
struct Data {
32+
IERC20 sellToken;
33+
IERC20 buyToken;
34+
address receiver;
35+
uint256 sellAmount;
36+
uint256 minBuyAmount; // minimum amount of buyToken to receive;
37+
uint256 t0; // start valide date of the order
38+
uint256 t; // maximum date for the order to be valid
39+
bytes32 polymarketOrderHash; // hash of the Polymarket order
40+
}
41+
42+
// --- functions
43+
44+
/**
45+
* @dev revert if the order is invalid
46+
* @param self The PolyswapOrder order to validate
47+
*/
48+
function validate(Data memory self, Trading polymarket) internal view {
49+
if (!(self.sellToken != self.buyToken)) revert IConditionalOrder.OrderNotValid(INVALID_SAME_TOKEN);
50+
if (!(address(self.sellToken) != address(0) && address(self.buyToken) != address(0))) {
51+
revert IConditionalOrder.OrderNotValid(INVALID_TOKEN);
52+
}
53+
if (!(self.t0 > block.timestamp)) revert IConditionalOrder.OrderNotValid(INVALID_START_DATE);
54+
if (!(self.t > self.t0 && self.t < type(uint32).max)) revert IConditionalOrder.OrderNotValid(INVALID_END_DATE);
55+
if (!(self.sellAmount > 0)) revert IConditionalOrder.OrderNotValid(INVALID_SELL_AMOUNT);
56+
if (!(self.minBuyAmount > 0)) revert IConditionalOrder.OrderNotValid(INVALID_MIN_BUY_AMOUNT);
57+
58+
// Check if the Polymarket order is valid and not filled or cancelled.
59+
if (!(self.polymarketOrderHash == 0)) revert IConditionalOrder.OrderNotValid(INVALID_POLYMARKET_ORDER_HASH);
60+
OrderStatus memory order = polymarket.getOrderStatus(self.polymarketOrderHash);
61+
if (!(order.remaining != 0 || order.isFilledOrCancelled == false)) {
62+
revert IConditionalOrder.OrderNotValid(INVALID_POLYMARKET_ORDER_HASH);
63+
}
64+
}
65+
66+
/**
67+
* @dev Generate the `GPv2Order` of the Polyswap order.
68+
* @param self The Polyswap order to generate the order for.
69+
* @return order The `GPv2Order` of the Polyswap order.
70+
*/
71+
function orderFor(Data memory self, Trading polymarket) internal view returns (GPv2Order.Data memory order) {
72+
// First, validate and revert if the order is invalid.
73+
validate(self, polymarket);
74+
75+
order = GPv2Order.Data({
76+
sellToken: self.sellToken,
77+
buyToken: self.buyToken,
78+
receiver: self.receiver,
79+
sellAmount: self.sellAmount,
80+
buyAmount: self.minBuyAmount,
81+
validTo: uint32(self.t),
82+
appData: self.polymarketOrderHash,
83+
feeAmount: 0,
84+
kind: GPv2Order.KIND_SELL,
85+
partiallyFillable: false,
86+
sellTokenBalance: GPv2Order.BALANCE_ERC20,
87+
buyTokenBalance: GPv2Order.BALANCE_ERC20
88+
});
89+
}
90+
}

0 commit comments

Comments
 (0)