Skip to content

Commit

Permalink
does not compile
Browse files Browse the repository at this point in the history
  • Loading branch information
0xferit committed Oct 9, 2024
1 parent dbbbf02 commit 88bd783
Show file tree
Hide file tree
Showing 7 changed files with 1,425 additions and 0 deletions.
433 changes: 433 additions & 0 deletions src/ConditionalTokens/CTHelpers.sol

Large diffs are not rendered by default.

248 changes: 248 additions & 0 deletions src/ConditionalTokens/ConditionalTokens.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,248 @@
// SPDX-License-Identifier: GPL-3.0
// This file is part of Ghee.
//
// Ghee is a derivative work of ConditionalTokens by Gnosis.
//
// The original file was obtained from https://github.com/gnosis/conditional-tokens-contracts/tree/eeefca66eb46c800a9aaab88db2064a99026fde5.

pragma solidity ^0.8.1;
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { ERC1155 } from "@openzeppelin/contracts/token/ERC1155/ERC1155.sol";
import { CTHelpers } from "./CTHelpers.sol";

contract ConditionalTokens is ERC1155 {
event ConditionPreparation(
bytes32 indexed conditionId,
address indexed oracle,
bytes32 indexed questionId,
uint outcomeSlotCount
);

event ConditionResolution(
bytes32 indexed conditionId,
address indexed oracle,
bytes32 indexed questionId,
uint outcomeSlotCount,
uint[] payoutNumerators
);

event PositionSplit(
address indexed stakeholder,
IERC20 collateralToken,
bytes32 indexed parentCollectionId,
bytes32 indexed conditionId,
uint[] partition,
uint amount
);

event PositionsMerge(
address indexed stakeholder,
IERC20 collateralToken,
bytes32 indexed parentCollectionId,
bytes32 indexed conditionId,
uint[] partition,
uint amount
);

event PayoutRedemption(
address indexed redeemer,
IERC20 indexed collateralToken,
bytes32 indexed parentCollectionId,
bytes32 conditionId,
uint[] indexSets,
uint payout
);

mapping(bytes32 => uint[]) public payoutNumerators;
mapping(bytes32 => uint) public payoutDenominator;

constructor() ERC1155("") {}

function prepareCondition(address oracle, bytes32 questionId, uint outcomeSlotCount) external {
require(outcomeSlotCount <= 256, "Too many outcome slots");
require(outcomeSlotCount > 1, "There should be more than one outcome slot");
bytes32 conditionId = CTHelpers.getConditionId(oracle, questionId, outcomeSlotCount);
require(payoutNumerators[conditionId].length == 0, "Condition already prepared");
payoutNumerators[conditionId] = new uint[](outcomeSlotCount);
emit ConditionPreparation(conditionId, oracle, questionId, outcomeSlotCount);
}

function reportPayouts(bytes32 questionId, uint[] calldata payouts) external {
uint outcomeSlotCount = payouts.length;
require(outcomeSlotCount > 1, "There should be more than one outcome slot");
bytes32 conditionId = CTHelpers.getConditionId(msg.sender, questionId, outcomeSlotCount);
require(payoutNumerators[conditionId].length == outcomeSlotCount, "Condition not prepared or found");
require(payoutDenominator[conditionId] == 0, "Payout denominator already set");

uint den = 0;
for (uint i = 0; i < outcomeSlotCount; i++) {
uint num = payouts[i];
den += num;
require(payoutNumerators[conditionId][i] == 0, "Payout numerator already set");
payoutNumerators[conditionId][i] = num;
}
require(den > 0, "Payout is all zeroes");
payoutDenominator[conditionId] = den;
emit ConditionResolution(conditionId, msg.sender, questionId, outcomeSlotCount, payoutNumerators[conditionId]);
}

function splitPosition(
IERC20 collateralToken,
bytes32 parentCollectionId,
bytes32 conditionId,
uint[] calldata partition,
uint amount
) external {
require(partition.length > 1, "Got empty or singleton partition");
uint outcomeSlotCount = payoutNumerators[conditionId].length;
require(outcomeSlotCount > 0, "Condition not prepared yet");

uint fullIndexSet = (1 << outcomeSlotCount) - 1;
uint freeIndexSet = fullIndexSet;
uint[] memory positionIds = new uint[](partition.length);
uint[] memory amounts = new uint[](partition.length);
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;
positionIds[i] = CTHelpers.getPositionId(collateralToken, CTHelpers.getCollectionId(parentCollectionId, conditionId, indexSet));
amounts[i] = 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,
CTHelpers.getPositionId(collateralToken, parentCollectionId),
amount
);
}
} else {
_burn(
msg.sender,
CTHelpers.getPositionId(collateralToken,
CTHelpers.getCollectionId(parentCollectionId, conditionId, fullIndexSet ^ freeIndexSet)),
amount
);
}

_mintBatch(
msg.sender,
positionIds,
amounts,
""
);
emit PositionSplit(msg.sender, collateralToken, parentCollectionId, conditionId, partition, amount);
}

function mergePositions(
IERC20 collateralToken,
bytes32 parentCollectionId,
bytes32 conditionId,
uint[] calldata partition,
uint amount
) external {
require(partition.length > 1, "Got empty or singleton partition");
uint outcomeSlotCount = payoutNumerators[conditionId].length;
require(outcomeSlotCount > 0, "Condition not prepared yet");

uint fullIndexSet = (1 << outcomeSlotCount) - 1;
uint freeIndexSet = fullIndexSet;
uint[] memory positionIds = new uint[](partition.length);
uint[] memory amounts = new uint[](partition.length);
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;
positionIds[i] = CTHelpers.getPositionId(collateralToken, CTHelpers.getCollectionId(parentCollectionId, conditionId, indexSet));
amounts[i] = amount;
}
_burnBatch(
msg.sender,
positionIds,
amounts
);

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

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

function redeemPositions(IERC20 collateralToken, bytes32 parentCollectionId, bytes32 conditionId, uint[] calldata indexSets) external {
uint den = payoutDenominator[conditionId];
require(den > 0, "Result for condition not received yet");
uint outcomeSlotCount = payoutNumerators[conditionId].length;
require(outcomeSlotCount > 0, "Condition not prepared yet");

uint totalPayout = 0;

uint fullIndexSet = (1 << outcomeSlotCount) - 1;
for (uint i = 0; i < indexSets.length; i++) {
uint indexSet = indexSets[i];
require(indexSet > 0 && indexSet < fullIndexSet, "Got invalid index set");
uint positionId = CTHelpers.getPositionId(collateralToken,
CTHelpers.getCollectionId(parentCollectionId, conditionId, indexSet));

uint payoutNumerator = 0;
for (uint j = 0; j < outcomeSlotCount; j++) {
if (indexSet & (1 << j) != 0) {
payoutNumerator += payoutNumerators[conditionId][j];
}
}

uint payoutStake = balanceOf(msg.sender, positionId);
if (payoutStake > 0) {
totalPayout += payoutStake * payoutNumerator / den;
_burn(msg.sender, positionId, payoutStake);
}
}

if (totalPayout > 0) {
if (parentCollectionId == bytes32(0)) {
require(collateralToken.transfer(msg.sender, totalPayout), "Could not transfer payout to message sender");
} else {
_mint(msg.sender, CTHelpers.getPositionId(collateralToken, parentCollectionId), totalPayout, "");
}
}
emit PayoutRedemption(msg.sender, collateralToken, parentCollectionId, conditionId, indexSets, totalPayout);
}

function getOutcomeSlotCount(bytes32 conditionId) external view returns (uint) {
return payoutNumerators[conditionId].length;
}

function getConditionId(address oracle, bytes32 questionId, uint outcomeSlotCount) external pure returns (bytes32) {
return CTHelpers.getConditionId(oracle, questionId, outcomeSlotCount);
}

function getCollectionId(bytes32 parentCollectionId, bytes32 conditionId, uint indexSet) external view returns (bytes32) {
return CTHelpers.getCollectionId(parentCollectionId, conditionId, indexSet);
}

function getPositionId(IERC20 collateralToken, bytes32 collectionId) external pure returns (uint) {
return CTHelpers.getPositionId(collateralToken, collectionId);
}
}
Loading

0 comments on commit 88bd783

Please sign in to comment.