forked from Polymarket/ctf-exchange-v2
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathCtfCollateralAdapter.sol
More file actions
200 lines (165 loc) · 7.95 KB
/
Copy pathCtfCollateralAdapter.sol
File metadata and controls
200 lines (165 loc) · 7.95 KB
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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.34;
import { SafeTransferLib } from "@solady/src/utils/SafeTransferLib.sol";
import { IConditionalTokens } from "@ctf-exchange-v2/src/adapters/interfaces/IConditionalTokens.sol";
import { CTFHelpers } from "@ctf-exchange-v2/src/adapters/libraries/CTFHelpers.sol";
import { CollateralToken } from "@ctf-exchange-v2/src/collateral/CollateralToken.sol";
import { Pausable } from "@ctf-exchange-v2/src/collateral/abstract/Pausable.sol";
import { ERC1155TokenReceiver } from "@ctf-exchange-v2/src/exchange/mixins/ERC1155TokenReceiver.sol";
/// @title CtfCollateralAdapter
/// @author Polymarket
/// @notice An adapter for interfacing with ConditionalTokens Markets
/// using the PolymarketCollateralToken
contract CtfCollateralAdapter is Pausable, ERC1155TokenReceiver {
using SafeTransferLib for address;
/*--------------------------------------------------------------
STATE
--------------------------------------------------------------*/
/// @notice The legacy Conditional Tokens Framework contract.
IConditionalTokens public immutable CONDITIONAL_TOKENS;
/// @notice The collateral token (PMCT) contract address.
address public immutable COLLATERAL_TOKEN;
/// @notice The USDC.e token address.
address public immutable USDCE;
/*--------------------------------------------------------------
CONSTRUCTOR
--------------------------------------------------------------*/
/// @notice Deploys the CTF collateral adapter.
/// @param _owner The contract owner.
/// @param _admin The initial admin address.
/// @param _conditionalTokens The legacy CTF contract address.
/// @param _collateralToken The collateral token (PMCT) address.
/// @param _usdce The USDC.e token address.
constructor(address _owner, address _admin, address _conditionalTokens, address _collateralToken, address _usdce) {
CONDITIONAL_TOKENS = IConditionalTokens(_conditionalTokens);
COLLATERAL_TOKEN = _collateralToken;
USDCE = _usdce;
_initializeOwner(_owner);
_grantRoles(_admin, ADMIN_ROLE);
_usdce.safeApprove(_conditionalTokens, type(uint256).max);
}
/*--------------------------------------------------------------
EXTERNAL
--------------------------------------------------------------*/
/// @notice Splits collateral into conditional token positions
/// @dev Unnamed params retained for IConditionalTokens interface compatibility
/// @param _conditionId The condition ID to split on
/// @param _amount The amount of collateral to split
function splitPosition(address, bytes32, bytes32 _conditionId, uint256[] calldata, uint256 _amount)
external
onlyUnpaused(USDCE)
{
COLLATERAL_TOKEN.safeTransferFrom(msg.sender, COLLATERAL_TOKEN, _amount);
// forgefmt: disable-next-item
CollateralToken(COLLATERAL_TOKEN).unwrap({
_asset: USDCE,
_to: address(this),
_amount: _amount,
_callbackReceiver: address(0),
_data: ""
});
_splitPosition(_conditionId, _amount);
uint256[] memory positionIds = _getPositionIds(_conditionId);
uint256[] memory amounts = new uint256[](2);
amounts[0] = _amount;
amounts[1] = _amount;
CONDITIONAL_TOKENS.safeBatchTransferFrom(address(this), msg.sender, positionIds, amounts, "");
}
/// @notice Merges conditional token positions back into collateral
/// @dev Unnamed params retained for IConditionalTokens interface compatibility
/// @param _conditionId The condition ID to merge on
/// @param _amount The amount of each position to merge
function mergePositions(address, bytes32, bytes32 _conditionId, uint256[] calldata, uint256 _amount)
external
onlyUnpaused(USDCE)
{
uint256[] memory positionIds = _getPositionIds(_conditionId);
uint256[] memory amounts = new uint256[](2);
amounts[0] = _amount;
amounts[1] = _amount;
CONDITIONAL_TOKENS.safeBatchTransferFrom(msg.sender, address(this), positionIds, amounts, "");
_mergePositions(_conditionId, _amount);
USDCE.safeTransfer(COLLATERAL_TOKEN, _amount);
// forgefmt: disable-next-item
CollateralToken(COLLATERAL_TOKEN).wrap({
_asset: USDCE,
_to: msg.sender,
_amount: _amount,
_callbackReceiver: address(0),
_data: ""
});
}
/// @notice Redeems conditional token positions for collateral after resolution
/// @dev Unnamed params retained for IConditionalTokens interface compatibility
/// @param _conditionId The condition ID to redeem
function redeemPositions(address, bytes32, bytes32 _conditionId, uint256[] calldata) external onlyUnpaused(USDCE) {
uint256[] memory positionIds = _getPositionIds(_conditionId);
uint256[] memory amounts = new uint256[](2);
amounts[0] = CONDITIONAL_TOKENS.balanceOf(msg.sender, positionIds[0]);
amounts[1] = CONDITIONAL_TOKENS.balanceOf(msg.sender, positionIds[1]);
CONDITIONAL_TOKENS.safeBatchTransferFrom(msg.sender, address(this), positionIds, amounts, "");
_redeemPositions(_conditionId, CTFHelpers.partition());
uint256 amount = USDCE.balanceOf(address(this));
USDCE.safeTransfer(COLLATERAL_TOKEN, amount);
// forgefmt: disable-next-item
CollateralToken(COLLATERAL_TOKEN).wrap({
_asset: USDCE,
_to: msg.sender,
_amount: amount,
_callbackReceiver: address(0),
_data: ""
});
}
/*--------------------------------------------------------------
ONLY ADMIN
--------------------------------------------------------------*/
/// @notice Adds a new admin
/// @param _admin The address of the new admin
function addAdmin(address _admin) external onlyRoles(ADMIN_ROLE) {
_grantRoles(_admin, ADMIN_ROLE);
}
/// @notice Removes an admin
/// @param _admin The address of the admin to remove
function removeAdmin(address _admin) external onlyRoles(ADMIN_ROLE) {
_removeRoles(_admin, ADMIN_ROLE);
}
/*--------------------------------------------------------------
INTERNAL
--------------------------------------------------------------*/
/// @dev Returns the YES and NO position IDs for a condition.
function _getPositionIds(bytes32 _conditionId) internal view virtual returns (uint256[] memory) {
return CTFHelpers.positionIds(USDCE, _conditionId);
}
/// @dev Splits collateral into positions via the legacy CTF.
function _splitPosition(bytes32 _conditionId, uint256 _amount) internal virtual {
// forgefmt: disable-next-item
CONDITIONAL_TOKENS.splitPosition({
collateralToken: USDCE,
parentCollectionId: bytes32(0),
conditionId: _conditionId,
partition: CTFHelpers.partition(),
amount: _amount
});
}
/// @dev Merges positions back into collateral via the legacy CTF.
function _mergePositions(bytes32 _conditionId, uint256 _amount) internal virtual {
// forgefmt: disable-next-item
CONDITIONAL_TOKENS.mergePositions({
collateralToken: USDCE,
parentCollectionId: bytes32(0),
conditionId: _conditionId,
partition: CTFHelpers.partition(),
amount: _amount
});
}
/// @dev Redeems resolved positions via the legacy CTF.
function _redeemPositions(bytes32 _conditionId, uint256[] memory indexSets) internal virtual {
// forgefmt: disable-next-item
CONDITIONAL_TOKENS.redeemPositions({
collateralToken: USDCE,
parentCollectionId: bytes32(0),
conditionId: _conditionId,
indexSets: indexSets
});
}
}