Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat comment #6

Merged
merged 16 commits into from
Dec 8, 2023
14 changes: 6 additions & 8 deletions src/core/Arena.sol
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,7 @@ import { DeploymentParams } from "core/params/coreParams.sol";
import { SToken } from "core/token/SToken.sol";
import { getAdjustPrice } from "core/utils.sol";

/// @notice Deploys battles. Sets pool underlying, collateral, fees and other
/// deployment
/// parameters.
/// @notice Deploys battles. Sets pool underlying, collateral, fees, expiries and other deployment parameters.
contract Arena is IArena, Ownable {
address public oracleAddr;
address public managerAddr;
Expand Down Expand Up @@ -86,27 +84,27 @@ contract Arena is IArena, Ownable {
if (msg.sender != ma) {
revert Errors.OnlyManager();
}
// collaterl address error
// checks for collateral address error
if (params.bk.collateral == address(0)) {
revert Errors.ZeroValue();
}

// not supported
// checks whether the collateral is supported
if (!isPermissionless) {
if (!collateralWhitelist[params.bk.collateral]) {
revert Errors.NotSupported();
}
}

// checks whether the underlying is supported
if (!underlyingWhitelist[params.bk.underlying]) {
revert Errors.NotSupported();
}

// expiries must at 8am utc
// requires expiries to be at 8am utc
if ((params.bk.expiries - 28_800) % 86_400 != 0 || block.timestamp >= params.bk.expiries) {
revert Errors.NotSupportedExpiries();
}

// requires strike prices to be non-zero and rounded accordingly
params.bk.strikeValue = getAdjustPrice(params.bk.strikeValue);
if (params.bk.strikeValue == 0) {
revert Errors.ZeroValue();
Expand Down
18 changes: 8 additions & 10 deletions src/core/Battle.sol
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ import {
} from "core/params/coreParams.sol";

/// @title Battle
/// @notice Each options pool is contained in a Battle contract. Battle contracts provide core functionalities including minting and burning
/// liquidity, trading options tokens, settling and exercising options, and withdrawing collateral reserved for settlement.

contract Battle is IBattle {
using Tick for mapping(int24 => TickInfo);
using TickBitmap for mapping(int16 => uint256);
Expand Down Expand Up @@ -92,7 +95,7 @@ contract Battle is IBattle {
_;
}

/// @notice init storage state variable, only be caled once
/// @notice Initiates storage state variables. Only called once for a battle.
function init(DeploymentParams memory params) external override {
if (_bk.expiries != 0) {
revert Errors.InitTwice();
Expand Down Expand Up @@ -311,7 +314,7 @@ contract Battle is IBattle {
state.amountSpecifiedRemaining += (step.amountOut).toInt256();
state.amountCalculated += (step.amountIn).toInt256();
}

// feeAmount is computed on a notional basis using amountOut
step.feeAmount = FullMath.mulDiv(step.amountOut, fee.transactionFee, 1e6);
if (cache.feeProtocol > 0) {
uint256 delta = FullMath.mulDiv(step.feeAmount, cache.feeProtocol, 1e6);
Expand All @@ -324,15 +327,10 @@ contract Battle is IBattle {
state.global.fee += FullMath.mulDiv(step.feeAmount, FixedPoint128.Q128, state.liquidity);
state.transactionFee += step.feeAmount;
state.global.collateralIn += FullMath.mulDiv(step.amountIn, FixedPoint128.Q128, state.liquidity);

// Updates all-time growth of spear or shield deltas in the global state
if (params.tradeType == TradeType.BUY_SPEAR) {
// buy spear => spearBought and shieldBankOut need be
// considered
// spear bought
state.global.spearOut += FullMath.mulDiv(step.amountOut, FixedPoint128.Q128, state.liquidity);
} else {
// buy shield => shieldBought and spearBankOut need be
// considered
state.global.shieldOut += FullMath.mulDiv(step.amountOut, FixedPoint128.Q128, state.liquidity);
}
}
Expand Down Expand Up @@ -381,10 +379,10 @@ contract Battle is IBattle {
}

if (params.tradeType == TradeType.BUY_SPEAR) {
// mint spear to user
// mints spear tokens to the buyer
ISToken(spear).mint(params.recipient, sAmount);
} else {
// mint shield to user
// mints shield tokens to the buyer
ISToken(shield).mint(params.recipient, sAmount);
}
emit Traded(params.recipient, state.liquidity, cAmount, sAmount, params.tradeType, state.sqrtPriceX96, state.tick);
Expand Down
26 changes: 12 additions & 14 deletions src/core/Oracle.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,15 @@ import { AggregatorV3Interface } from "chainlink/interfaces/AggregatorV3Interfac
import { getAdjustPrice } from "./utils.sol";

/// @title Oracle
/// @notice Get external price by Oracle
/// @notice Retrieves underlying asset prices used for settling options.
contract Oracle is Ownable {
using SafeCast for int256;

mapping(string => address) private _externalOracleOf;
mapping(address => mapping(uint256 => uint256)) public fixPrices;

/// @notice Defines the underlying asset symbol and oracle address for a
/// pool. Only called by the owner.
/// @param symbols The asset symbol for which to retrieve price feed
/// @notice Defines the underlying asset symbol and oracle address for a pool. Only called by the owner.
/// @param symbols The asset symbol for which to retrieve a price feed
/// @param oracles_ The external oracle address
function setExternalOracle(string[] calldata symbols, address[] calldata oracles_) external onlyOwner {
require(symbols.length == oracles_.length, "symbols not match oracles");
Expand All @@ -33,7 +32,7 @@ contract Oracle is Ownable {
}

/// @notice Gets and computes price from external oracles
/// @param cOracleAddr chainlink price contract
/// @param cOracleAddr the contract address for a chainlink price feed
/// @param ts Timestamp for the asset price
/// @return price The retrieved price
function getPriceByExternal(address cOracleAddr, uint256 ts) external view returns (uint256 price, uint256 actualTs) {
Expand All @@ -45,8 +44,9 @@ contract Oracle is Ownable {
uint256 decimalDiff = 10 ** (18 - cOracle.decimals());
(uint256 cPrice, uint256 cActualTs) = _getPrice(cOracle, roundID, ts, decimalDiff);

// If the price remains unreported or inaccessible an hour post expiry, the closest available price will be fixed based on the external oracle
// data.
if (block.timestamp - ts > 1 hours && cPrice == 0) {
// get price from setting
require(fixPrices[cOracleAddr][ts] != 0, "setting price");
price = fixPrices[cOracleAddr][ts];
actualTs = ts;
Expand All @@ -60,8 +60,7 @@ contract Oracle is Ownable {
/// @param cOracle Oracle interface for retrieving price feed
/// @param id The roundId using which price is retrieved
/// @param ts Timestamp for the asset price
/// @param decimalDiff Precision differences for the number of decimal
/// places of retrieved data
/// @param decimalDiff Precision differences for the number of decimal places of retrieved data
function _getPrice(
AggregatorV3Interface cOracle,
uint80 id,
Expand All @@ -72,22 +71,21 @@ contract Oracle is Ownable {
view
returns (uint256 finalPrice, uint256 finalTs)
{
// get next price after 8am utc
// get the next price after 8am utc
uint80 phaseId = _getPhaseIdFromRoundId(id);
uint80 startRoundId = _getStartRoundId(phaseId);
try AggregatorV3Interface(cOracle).getRoundData(startRoundId) returns (uint80, int256, uint256, uint256 updatedAt, uint80) {
//updatedAt == 0, invalid value
//The situation where 'startRound' occurs after the 'endTs' of a battle is a special case that will affect corrections.
//Therefore, it will simply return a value of 0. The correct price will be provided by 'fixPrices'.
//In case the 'startRound' occurs after the 'endTs' of a battle due to external oracle updates, it returns 0. The correct price will be
// provided by fixPrices.
if (updatedAt == 0 || updatedAt >= ts) {
return (0, 0);
} else {
// If the finalPrice is 0, then the price will be provided by fixPrices.
(finalPrice, finalTs) = _getPriceInPhase(cOracle, startRoundId, id, ts, decimalDiff);
}
} catch {
// If there are any errors encountered, then the correct price will be provided by the 'fixPrices'
// just return (0, 0)
// If there are any errors encountered, it returns (0, 0). the correct price will be provided by fixPrices.
}
}

Expand Down Expand Up @@ -126,7 +124,7 @@ contract Oracle is Ownable {
actualTs = updatedAt;
}
} catch {
// something is wrong
// in case of errors
return (0, 0);
}
}
Expand Down
7 changes: 3 additions & 4 deletions src/core/interfaces/IArena.sol
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,12 @@ interface IArenaAdmin {
interface IArenaCreation {
event BattleCreated(BattleKey bk, address battleAddr, address spear, address shield, Fee fee);

/// @notice create new battle
/// @param params Params for creating new battle
/// @notice Create a new battle
/// @param params Params for creating a new battle
/// @return battleAddr new battle address
function createBattle(CreateAndInitBattleParams memory params) external returns (address battleAddr);

/// @notice Get existed battle address by battleKey. If not exist, will
/// return address(0)
/// @notice Get the address of the existing battle or address(0) if not found
function getBattle(BattleKey memory battleKey) external view returns (address battleAddr);
}

Expand Down
6 changes: 2 additions & 4 deletions src/core/interfaces/IOracle.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,8 @@

pragma solidity ^0.8.0;

/// @title Get external price by oracle
/// @notice Collects and updates underlying asset prices used for settling
/// options.
/// It retrieves asset prices and supplies them to all contracts that use them.
/// @title Get price from external oracle
/// @notice Retrieves underlying asset prices used for settling options.
interface IOracle {
function getPriceByExternal(address cOracleAddr, uint256 ts) external view returns (uint256 price_, uint256 actualTs);

Expand Down
6 changes: 3 additions & 3 deletions src/core/interfaces/ISToken.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@ pragma solidity ^0.8.0;
/**
* @title ISToken
*
* @notice ISToken is a spear/shield that can be minted and burned by the battle contract.
* @notice Mints or burns Spear or Shield tokens
*/
interface ISToken {
/**
* @notice Mint `amount` of ISToken to `account`
* @notice Mint an amount of sToken to account
*/
function mint(address account, uint256 amount) external;
/**
* @notice Burn `amount` of ISToken from `account`
* @notice Burn an amount of sToken from account
*/
function burn(address account, uint256 amount) external;
}
73 changes: 31 additions & 42 deletions src/core/interfaces/battle/IBattleActions.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,34 +6,30 @@ import { BattleMintParams, BattleBurnParams, BattleTradeParams } from "core/para
import { PositionInfo, TradeType, Outcome, LiquidityType } from "core/types/common.sol";

interface IBattleMintBurn {
/// @param sender The address who minted the liquidity
/// @param liquidityType The type of liquidity minted
/// @param sender The address used for minting liquidity
/// @param liquidityType The type of token used as liquidity
/// @param tickLower The lower tick of the position
/// @param tickUpper The upper tick of the position
/// @param liquidity The amount of liquidity minted
/// @param seedAmount The amount of collateral/spear/shield(according to liquidityType) spent
/// @param seedAmount The amount of tokens used for minting liquidity, per collateral, spear or shield liquidityType
event Minted(address indexed sender, LiquidityType liquidityType, int24 tickLower, int24 tickUpper, uint128 liquidity, uint256 seedAmount);

/// @param tickLower The lower tick of the position
/// @param tickUpper The upper tick of the position
/// @param liquidityType The type of liquidity burned
/// @param liquidityType The type of token used as liquidity
/// @param liquidityAmount The amount of liquidity burned
event Burned(int24 tickLower, int24 tickUpper, LiquidityType liquidityType, uint128 liquidityAmount);

/// @notice Mint liquidity
/// @param mp The params of mint
/// @param mp The params for minting liquidity
function mint(BattleMintParams memory mp) external;

// / @notice Burn liquidity for a slot
// / @dev
// / @return spearAmount The amount of spear tokens to be removed from curve
// / @return shieldAmount The amount of shield tokens to be removed from
// curve
/// @notice Burn liquidity
/// @param BurnParams The params for burning liquidity
function burn(BattleBurnParams memory BurnParams) external;

/// @notice transfer collateral/spear/shield to lp
/// @dev only called by Manager contract
/// @param recipient The address who receive collateral/spear/shield
/// @notice Transfers collateral/spear/shield tokens to the liquidity provider. Only called by the manager contract
/// @param recipient The address who receive collateral/spear/shield tokens
/// @param cAmount The amount of collateral to be transfered
/// @param spAmount The amount of spear to be transfered
/// @param shAmount The amount of shield to be transfered
Expand All @@ -42,22 +38,23 @@ interface IBattleMintBurn {

/// @title IBattleTrade
interface IBattleTrade {
/// @notice trade spear/shield for collateral
/// @param recipient The address who receive spear/shield
/// @notice Swap collateral for spear or shield tokens
/// @param recipient The address who receive spear or shield tokens
/// @param liquidity liquity in battle after trade
/// @param amountIn The amount of spear/shield to be traded
/// @param amountOut The amount of collateral to be traded
/// @param tradeType buySpard or buyShield
/// @param sqrtPriceX96 The sqrt price of the battle after trade
/// @param tick The tick of the battle after trade
/// @param amountIn The amount of token input
/// @param amountOut The amount of token output
/// @param tradeType BUY_SPEAR or BUY_SHIELD
/// @param sqrtPriceX96 The sqrt price of the battle after the trade
/// @param tick The tick of the battle after the trade
event Traded(
address indexed recipient, uint128 liquidity, uint256 amountIn, uint256 amountOut, TradeType tradeType, uint160 sqrtPriceX96, int24 tick
);

/// @notice trade spear/shield for collateral
/// @param tp The params of trade
/// @return cAmount The amount of collateral user spent
/// @return sAmount The amount of spear/shield user received
/// @notice Swap collateral for spear or shield tokens
/// @param tp The params for the trade
/// @return cAmount The amount of collateral paid by the trader
/// @return sAmount The amount of spear or shield tokens received by the trader
/// @return fAmount The amount of fee in collateral token to be spent for the trade
function trade(BattleTradeParams memory tp) external returns (uint256 cAmount, uint256 sAmount, uint256 fAmount);
}

Expand All @@ -72,30 +69,22 @@ interface IBattleBase {

event ProtocolFeeCollected(address recipient, uint256 amount);

/// @notice settle the battle
/// battle will fetch the price of underlying asset, and determinate the
/// battle result.
/// battle finished after settle function was called
/// @notice Settles the battle and determines the outcome.
/// The Battle contract will fetch the price of underlying asset, and determines the outcome.
/// Once settled, a pool's address is not reused for new battles
function settle() external;

/// @notice If a user bought some spear/shield and won, he can switch
/// spear/shield to collateral by 1:1 ratio.
/// eg. Alice bought 100 spear and the battle result was spear_win, she can
/// switch 100 collateral by call this
/// function
/// @notice After settlement, an in-the-money spear or shield token is exercised for one collateral.
/// eg. Alice bought 100 spear. If the outcome is spear_win, she can
/// claim 100 collateral minus an exercise fee by calling this function.
function exercise() external;

/// @notice Returns the amount of unused collateral to the options seller
/// after settlement. For options that expire
/// out-of-money, the amount of collateral obligation reserved prior to
/// settlement becomes exercisable. Only called
/// by
/// the Manager.
/// @param recipient address which receive collateral
/// @param amount the amount of collateral will receive
/// @notice Enables the liquidity provider to withdraw the collateral amount reserved for settlement. Only called by the manager contract.
/// @param recipient The liquidity provider address to receive collateral
/// @param amount the amount of collateral to be received
function withdrawObligation(address recipient, uint256 amount) external;

/// @notice collect protocol fee
/// @notice Allows the accumulated protocol fee to be collected. Can only be called by the owner.
function collectProtocolFee(address recipient) external;
}

Expand Down
10 changes: 5 additions & 5 deletions src/core/interfaces/battle/IBattleState.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,16 @@ pragma solidity ^0.8.0;
import "core/types/common.sol";

interface IBattleState {
/// @notice Get slotInfo by slotKey.
/// @param pk positon key check how slotKey is generated in Position.sol
/// @param info check PositionInfo in PositionTypes.sol
/// @notice Retrieves position info for a given position key
/// @param pk positon key
/// @param info Information about the position
function positions(bytes32 pk) external view returns (PositionInfo memory info);

/// @notice The result of battle.
/// @return result check different battle result type in Outcome.sol
/// @return result check different battle result type in enums.sol
function battleOutcome() external view returns (Outcome);

/// @notice A battleKey can uniquely identify a battle
/// @notice Returns the BattleKey that uniquely identifies a battle
function battleKey() external view returns (BattleKey memory key);

/// @notice Get Manager address in this battle
Expand Down
Loading
Loading