Skip to content

Commit

Permalink
Merge branch 'master' into oracle-reporting
Browse files Browse the repository at this point in the history
  • Loading branch information
cag authored Jul 31, 2019
2 parents c1ae67c + bd210a7 commit ca5d627
Show file tree
Hide file tree
Showing 4 changed files with 317 additions and 26 deletions.
1 change: 0 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ before_install:
before_script: greenkeeper-lockfile-update
script:
- npm run lint
- npm run lint-contracts
- npm test
- npx codechecks
after_script: greenkeeper-lockfile-upload
193 changes: 175 additions & 18 deletions contracts/ConditionalTokens.sol
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
pragma solidity ^0.5.1;
import { IERC20 } from "openzeppelin-solidity/contracts/token/ERC20/IERC20.sol";
import { IERC1155TokenReceiver } from "./ERC1155/IERC1155TokenReceiver.sol";
import { ERC1155TokenReceiver } from "./ERC1155/ERC1155TokenReceiver.sol";
import { IERC1155 } from "./ERC1155/IERC1155.sol";
import { ERC1155 } from "./ERC1155/ERC1155.sol";


contract ConditionalTokens is ERC1155 {
contract ConditionalTokens is ERC1155, ERC1155TokenReceiver {

/// @dev Emitted upon the successful preparation of a condition.
/// @param conditionId The condition's ID. This ID may be derived from the other three parameters via ``keccak256(abi.encodePacked(oracle, questionId, outcomeSlotCount))``.
Expand Down Expand Up @@ -37,6 +39,15 @@ contract ConditionalTokens is ERC1155 {
uint[] partition,
uint amount
);
event PositionSplit(
address indexed stakeholder,
IERC1155 collateralToken,
uint collateralTokenID,
bytes32 indexed parentCollectionId,
bytes32 indexed conditionId,
uint[] partition,
uint amount
);
/// @dev Emitted when positions are successfully merged.
event PositionsMerge(
address indexed stakeholder,
Expand All @@ -46,6 +57,15 @@ contract ConditionalTokens is ERC1155 {
uint[] partition,
uint amount
);
event PositionsMerge(
address indexed stakeholder,
IERC1155 collateralToken,
uint collateralTokenID,
bytes32 indexed parentCollectionId,
bytes32 indexed conditionId,
uint[] partition,
uint amount
);
event PayoutRedemption(
address indexed redeemer,
IERC20 indexed collateralToken,
Expand All @@ -55,6 +75,8 @@ contract ConditionalTokens is ERC1155 {
uint payout
);

enum CollateralTypes { ERC20, ERC1155 }

/// Mapping key is an condition ID. Value represents numerators of the payout vector associated with the condition. This array is initialized with a length equal to the outcome slot count.
mapping(bytes32 => uint[]) public payoutNumerators;
mapping(bytes32 => uint) public payoutDenominatorForCondition;
Expand Down Expand Up @@ -108,6 +130,69 @@ contract ConditionalTokens is ERC1155 {
bytes32 conditionId,
uint[] calldata partition,
uint amount
) external {
(uint fullIndexSet, uint freeIndexSet) = mintSet(msg.sender, CollateralTypes.ERC20, address(collateralToken), 0, parentCollectionId, conditionId, partition, amount);

if (freeIndexSet == 0) {
if (parentCollectionId == bytes32(0)) {
require(collateralToken.transferFrom(msg.sender, address(this), amount), "could not receive collateral tokens");
} else {
_burn(
msg.sender,
getPositionId(collateralToken, parentCollectionId),
amount
);
}
} else {
_burn(
msg.sender,
getPositionId(collateralToken,
getCollectionId(parentCollectionId, conditionId, fullIndexSet ^ freeIndexSet)),
amount
);
}

emit PositionSplit(msg.sender, collateralToken, parentCollectionId, conditionId, partition, amount);
}

function split1155Position(
IERC1155 collateralToken,
uint collateralTokenID,
bytes32 parentCollectionId,
bytes32 conditionId,
uint[] calldata partition,
uint amount
) external {
(uint fullIndexSet, uint freeIndexSet) = mintSet(msg.sender, CollateralTypes.ERC1155, address(collateralToken), collateralTokenID, parentCollectionId, conditionId, partition, amount);

if (freeIndexSet == 0) {
if (parentCollectionId == bytes32(0)) {
collateralToken.safeTransferFrom(msg.sender, address(this), collateralTokenID, amount, "");
} else {
_burn(
msg.sender,
getPositionId(collateralToken, collateralTokenID, parentCollectionId),
amount
);
}
} else {
_burn(
msg.sender,
getPositionId(collateralToken, collateralTokenID,
getCollectionId(parentCollectionId, conditionId, fullIndexSet ^ freeIndexSet)),
amount
);
}

emit PositionSplit(msg.sender, collateralToken, collateralTokenID, parentCollectionId, conditionId, partition, amount);
}

function mergePositions(
IERC20 collateralToken,
bytes32 parentCollectionId,
bytes32 conditionId,
uint[] calldata partition,
uint amount
) external {
uint outcomeSlotCount = payoutNumerators[conditionId].length;
require(outcomeSlotCount > 0, "condition not prepared yet");
Expand All @@ -119,38 +204,40 @@ contract ConditionalTokens is ERC1155 {
require(indexSet > 0 && indexSet < fullIndexSet, "got invalid index set");
require((indexSet & freeIndexSet) == indexSet, "partition not disjoint");
freeIndexSet ^= indexSet;
_mint(
_burn(
msg.sender,
getPositionId(collateralToken, getCollectionId(parentCollectionId, conditionId, indexSet)),
amount,
""
amount
);
}

if (freeIndexSet == 0) {
if (parentCollectionId == bytes32(0)) {
require(collateralToken.transferFrom(msg.sender, address(this), amount), "could not receive collateral tokens");
require(collateralToken.transfer(msg.sender, amount), "could not send collateral tokens");
} else {
_burn(
_mint(
msg.sender,
getPositionId(collateralToken, parentCollectionId),
amount
amount,
""
);
}
} else {
_burn(
_mint(
msg.sender,
getPositionId(collateralToken,
getCollectionId(parentCollectionId, conditionId, fullIndexSet ^ freeIndexSet)),
amount
amount,
""
);
}

emit PositionSplit(msg.sender, collateralToken, parentCollectionId, conditionId, partition, amount);
emit PositionsMerge(msg.sender, collateralToken, parentCollectionId, conditionId, partition, amount);
}

function mergePositions(
IERC20 collateralToken,
function merge1155Positions(
IERC1155 collateralToken,
uint collateralTokenID,
bytes32 parentCollectionId,
bytes32 conditionId,
uint[] calldata partition,
Expand All @@ -168,33 +255,67 @@ contract ConditionalTokens is ERC1155 {
freeIndexSet ^= indexSet;
_burn(
msg.sender,
getPositionId(collateralToken, getCollectionId(parentCollectionId, conditionId, indexSet)),
getPositionId(collateralToken, collateralTokenID,
getCollectionId(parentCollectionId, conditionId, indexSet)),
amount
);
}

if (freeIndexSet == 0) {
if (parentCollectionId == bytes32(0)) {
require(collateralToken.transfer(msg.sender, amount), "could not send collateral tokens");
collateralToken.safeTransferFrom(address(this), msg.sender, collateralTokenID, amount, "");
} else {
_mint(
msg.sender,
getPositionId(collateralToken, parentCollectionId),
getPositionId(collateralToken, collateralTokenID, parentCollectionId),
amount,
""
);
}
} else {
_mint(
msg.sender,
getPositionId(collateralToken,
getPositionId(collateralToken, collateralTokenID,
getCollectionId(parentCollectionId, conditionId, fullIndexSet ^ freeIndexSet)),
amount,
""
);
}

emit PositionsMerge(msg.sender, collateralToken, parentCollectionId, conditionId, partition, amount);
emit PositionsMerge(msg.sender, collateralToken, collateralTokenID, parentCollectionId, conditionId, partition, amount);
}

function mintSet(
address recipient,
CollateralTypes collateralType,
address collateralToken,
uint collateralTokenID,
bytes32 parentCollectionId,
bytes32 conditionId,
uint[] memory partition,
uint amount
) private returns (uint fullIndexSet, uint freeIndexSet) {
{
uint outcomeSlotCount = payoutNumerators[conditionId].length;
require(outcomeSlotCount > 0, "condition not prepared yet");
fullIndexSet = (1 << outcomeSlotCount) - 1;
freeIndexSet = fullIndexSet;
}

for (uint i = 0; i < partition.length; i++) {
uint indexSet = partition[i];
require(indexSet > 0 && indexSet < fullIndexSet, "got invalid index set");
require((indexSet & freeIndexSet) == indexSet, "partition not disjoint");
freeIndexSet ^= indexSet;
_mint(
recipient,
collateralType == CollateralTypes.ERC20 ?
getPositionId(IERC20(collateralToken), getCollectionId(parentCollectionId, conditionId, indexSet)) :
getPositionId(IERC1155(collateralToken), collateralTokenID, getCollectionId(parentCollectionId, conditionId, indexSet)),
amount,
""
);
}
}

function redeemPositions(IERC20 collateralToken, bytes32 parentCollectionId, bytes32 conditionId, uint[] calldata indexSets) external {
Expand Down Expand Up @@ -236,6 +357,37 @@ contract ConditionalTokens is ERC1155 {
emit PayoutRedemption(msg.sender, collateralToken, parentCollectionId, conditionId, indexSets, totalPayout);
}

function onERC1155Received(
address operator,
address /* from */,
uint256 id,
uint256 value,
bytes calldata data
)
external
returns (bytes4)
{
if(operator != address(this)) {
(bytes32 conditionId, uint[] memory partition) = abi.decode(data, (bytes32, uint[]));
mintSet(operator, CollateralTypes.ERC1155, msg.sender, id, bytes32(0), conditionId, partition, value);
}

return this.onERC1155Received.selector;
}

function onERC1155BatchReceived(
address operator,
address /* from */,
uint256[] calldata ids,
uint256[] calldata values,
bytes calldata data
)
external
returns (bytes4)
{
revert("operation not supported");
}

/// @dev Gets the outcome slot count of a condition.
/// @param conditionId ID of the condition.
/// @return Number of outcome slots associated with a condition, or zero if condition has not been prepared yet.
Expand Down Expand Up @@ -268,4 +420,9 @@ contract ConditionalTokens is ERC1155 {
/// @param collectionId ID of the outcome collection associated with this position.
function getPositionId(IERC20 collateralToken, bytes32 collectionId) public pure returns (uint) {
return uint(keccak256(abi.encodePacked(collateralToken, collectionId)));
}}
}

function getPositionId(IERC1155 collateralToken, uint collateralTokenID, bytes32 collectionId) public pure returns (uint) {
return uint(keccak256(abi.encodePacked(collateralToken, collateralTokenID, collectionId)));
}
}
4 changes: 0 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,6 @@
"*.js": [
"eslint --fix",
"git add"
],
"*.sol": [
"solium --fix -f",
"git add"
]
}
}
Loading

0 comments on commit ca5d627

Please sign in to comment.