Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions packages/evm-contracts/contracts/lvr_amm/LvrMarket.sol
Original file line number Diff line number Diff line change
Expand Up @@ -127,14 +127,14 @@ contract LvrMarket is ReentrancyGuard {
function settleMarket() external isRouter nonReentrant {
require(state == MarketState.PENDING, "Invalid Market State");
require(block.timestamp >= resolutionTimestamp, "Challenge Window Open");
// Return bond to proposer with Reward collected through market fees
state = MarketState.RESOLVED;
IERC20(collateralToken).safeTransfer(proposer, bondValue); // Add fees and then reward the proposer

emit MarketSettled(outcome, proposer, bondValue);
_settleFromOracle();
}

function settleFromOracle() external isRouter nonReentrant {
_settleFromOracle();
}

function _settleFromOracle() private {
require(state == MarketState.OPEN || state == MarketState.PENDING || state == MarketState.DISPUTED, "Invalid Market State");

// Capture proposer's outcome before overwriting (for bond slashing)
Expand Down
55 changes: 55 additions & 0 deletions packages/evm-contracts/test/LvrMarket.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,61 @@ contract LvrMarketTest is Test {
router.settleMarket(marketAddr);
}

function test_ManualSettlementCannotResolveWithoutOracleResult() public {
bytes32 duelKey = keccak256("manual-settle-no-oracle-result");

vm.prank(admin);
router.create("Manual Oracle Gate", "Desc", "Src", duelKey, false, DURATION, 100 * 10**18);
address marketAddr = _lastMarketAddress();
LvrMarket market = LvrMarket(marketAddr);

vm.warp(block.timestamp + DURATION);

uint256 bond = market.bondValue();
vm.prank(user1);
mUSD.approve(address(router), bond);
vm.prank(user1);
router.proposerOutcome(marketAddr, 0);

vm.warp(block.timestamp + 5 minutes + 1);

vm.expectRevert(bytes("Oracle duel not resolved"));
router.settleMarket(marketAddr);

(LvrMarket.MarketState currentState,,,,,,,) = market.getMarketDetails();
assertEq(uint256(currentState), uint256(LvrMarket.MarketState.PENDING), "market should stay pending");
}

function test_SettleMarketUsesOracleOutcomeAfterManualProposal() public {
bytes32 duelKey = keccak256("manual-settle-oracle-authority");
_setupOracleDuel(duelKey);

vm.prank(admin);
router.create("Manual Oracle Override", "Desc", "Src", duelKey, false, DURATION, 100 * 10**18);
address marketAddr = _lastMarketAddress();
LvrMarket market = LvrMarket(marketAddr);

vm.warp(block.timestamp + DURATION);

uint256 bond = market.bondValue();
vm.prank(user1);
mUSD.approve(address(router), bond);
vm.prank(user1);
router.proposerOutcome(marketAddr, 0);

_proposeAndFinalizeOracle(duelKey, DuelOutcomeOracle.Side.B);

uint256 treasuryBefore = mUSD.balanceOf(treasury);
uint256 proposerBefore = mUSD.balanceOf(user1);
router.settleMarket(marketAddr);

(LvrMarket.MarketState currentState,, uint256 mktOutcome,,,,,) = market.getMarketDetails();
assertEq(uint256(currentState), uint256(LvrMarket.MarketState.RESOLVED));
assertEq(mktOutcome, 1, "manual settlement must use the oracle outcome");
assertEq(mUSD.balanceOf(treasury), treasuryBefore + bond, "wrong proposer bond should be slashed");
assertEq(mUSD.balanceOf(user1), proposerBefore, "wrong proposer should not receive bond");
}

function test_RedeemCollateralPaysWinningSide() public {
bytes32 duelKey = keccak256("redeem-winning-side");
_setupOracleDuel(duelKey);
Expand Down
Loading