Contract Address Details

0x40e21b8837dF1858A5e9f75B3d859A404d0E6361

Vault Last Balance Update: Block #701906
Created by 0x14a076–da26cf at 0xbd76bd–5001ba

Balance

0 Ether

Fetching tokens...

This contract has been verified via Sourcify. View contract in Sourcify repository
Contract name:
Vault




Optimization enabled
false
Compiler version
v0.8.6+commit.11564f7e




EVM Version
berlin




Verified at
2022-01-26 21:54:13.615884Z

Contract source code

// SPDX-License-Identifier: BSD-3-Clause AND MIT
pragma solidity 0.8.6;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {IUSDC} from "./interfaces/IUSDC.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {FixedPoint} from "@uma/core/contracts/common/implementation/FixedPoint.sol";
import {IUniswapV2Factory} from "@uniswap/v2-core/contracts/interfaces/IUniswapV2Factory.sol";
import {IUniswapV2Pair} from "@uniswap/v2-core/contracts/interfaces/IUniswapV2Pair.sol";
import {IUniswapV2Router02} from "@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router02.sol";
import {LongShortPair} from "@uma/core/contracts/financial-templates/long-short-pair/LongShortPair.sol";
import {IERC900} from "./interfaces/IERC900.sol";
/**
* @title Domination Finance vault
* @notice Provide and withdraw dominance pair liquidity in fewer transactions.
*/
contract Vault {
using SafeERC20 for IERC20;
using SafeERC20 for IUSDC;
using FixedPoint for FixedPoint.Unsigned;
using FixedPoint for FixedPoint.Signed;
event VaultDeposited(address user, address lsp, uint amountUSDC);
enum WithdrawMode { Basic, Redeem, Settle }
/**
* @notice Deposit USDC into the vault. Convert it all into LSP liquidity
* @dev Keep params in usage order https://levelup.gitconnected.com/stack-too-deep-error-in-solidity-ca83326ff0f0
* @param usdcForArb Portion of supplied USDC to use for arbitrage. Will be deposited along with profits.
* @param tokensToBuyForArb If buying+redeeming to arb pools, amount of tokens. See arbitrage() for more detail.
* @param router Address of Uniswap, Quickswap, etc. router.
* @param priceDeviation_ FixedPoint.Unsigned fraction: maximum % difference between long+short and collateralPerPair
* @param lsp LongShortPair for the target dominance pair.
* @param amount How much USDC to supply.
* @param longStaking Optional. Staking contract for long LP token. Must be during staking window.
* @param shortStaking Optional. Staking contract for long LP token. Must be during staking window.
* @param deadline timestamp beyond which tx will revert.
*/
function deposit(
uint usdcForArb,
uint tokensToBuyForArb,
IUniswapV2Router02 router,
FixedPoint.Unsigned calldata priceDeviation_,
LongShortPair lsp,
Signature calldata usdcSignature,
uint amount,
IERC900 longStaking,
IERC900 shortStaking,
uint deadline
) public {
require(deadline >= block.timestamp, "EXPIRED"); // save gas, fail early
IUSDC USDC = IUSDC(address(lsp.collateralToken()));
if (hasSignature(usdcSignature)) {
USDC.permit(msg.sender, address(this), amount, deadline, usdcSignature.v, usdcSignature.r, usdcSignature.s);
}
USDC.safeTransferFrom(msg.sender, address(this), amount);
if (usdcForArb > 0) {
_arbitrage(usdcForArb, tokensToBuyForArb, lsp, router, deadline);
amount = USDC.balanceOf(address(this));
}
(uint tokensToMint, uint mintUSDC, uint longValue, uint shortValue) = computeLPAmounts(
router, priceDeviation_, lsp, amount
);
require(longValue + shortValue + mintUSDC <= amount, "BUG");
USDC.approve(address(lsp), mintUSDC);
lsp.create(tokensToMint);
USDC.approve(address(router), shortValue + longValue);
{ // pool and stake the long tokens.
// Avoid "stack to deep" error. Copy to top of stack.
IUniswapV2Router02 router_ = router;
IERC20 long = IERC20(lsp.longToken());
long.approve(address(router_), tokensToMint);
{
// Avoid "stack to deep" error. Copy to top of stack.
uint deadline_ = deadline;
address recipient =
address(longStaking) == address(0)
? msg.sender
: address(this);
router_.addLiquidity(
address(long),
address(USDC),
tokensToMint,
longValue,
tokensToMint,
longValue,
recipient,
deadline_
);
}
if (address(longStaking) != address(0)) {
IUniswapV2Factory factory = IUniswapV2Factory(router.factory());
IERC20 longLP = IERC20(factory.getPair(address(long), address(USDC)));
uint longLPAmount = longLP.balanceOf(address(this));
longLP.approve(address(longStaking), longLPAmount);
longStaking.stakeFor(msg.sender, longLPAmount);
}
}
{ // pool and stake short tokens
// Avoid "stack to deep" error. Copy to top of stack.
IUniswapV2Router02 router_ = router;
IERC20 short = IERC20(lsp.shortToken());
short.approve(address(router_), tokensToMint);
{
// Avoid "stack to deep" error. Copy to top of stack.
uint deadline_ = deadline;
address recipient =
address(shortStaking) == address(0)
? msg.sender
: address(this);
router_.addLiquidity(
address(short),
address(USDC),
tokensToMint,
shortValue,
tokensToMint,
shortValue,
recipient,
deadline_
);
}
if (address(shortStaking) != address(0)) {
IUniswapV2Factory factory = IUniswapV2Factory(router.factory());
IERC20 shortLP = IERC20(factory.getPair(address(short), address(USDC)));
uint shortLPAmount = shortLP.balanceOf(address(this));
shortLP.approve(address(shortStaking), shortLPAmount);
shortStaking.stakeFor(msg.sender, shortLPAmount);
}
}
emit VaultDeposited(msg.sender, address(lsp), amount);
}
/**
* @notice Compute the percent difference between collateralPerPair and the sum of synth prices.
* A nonzero difference indicates an arbitrage opportunity.
* @return [(long price + short price) - collateralPerPair] / collateralPerPair
*/
function priceDeviation (
FixedPoint.Unsigned memory long,
FixedPoint.Unsigned memory short,
FixedPoint.Unsigned memory collateralPerPair
) internal pure returns (FixedPoint.Unsigned memory) {
FixedPoint.Signed memory max = FixedPoint.fromUnsigned(collateralPerPair);
FixedPoint.Signed memory diff = FixedPoint.fromUnsigned(long.add(short)).sub(max);
return abs(diff.div(max));
}
///@notice absolute value for FixedPoint library
function abs(FixedPoint.Signed memory x) internal pure returns (FixedPoint.Unsigned memory) {
if (x.isLessThan(0)) {
return FixedPoint.fromSigned(FixedPoint.Signed(0).sub(x));
} else {
return FixedPoint.fromSigned(x);
}
}
///@notice an EIP-712 signature for use with Uniswap/USDC permits
struct Signature {
uint8 v;
bytes32 r;
bytes32 s;
}
function hasSignature(Signature calldata s) pure internal returns (bool) {
return s.v != 0 && s.r != 0 && s.s != 0;
}
/***
* @notice Redeem both long and short LP tokens for USDC. LP tokens must be unstaked first.
* @param priceDeviation_ FixedPoint.Unsigned fraction: maximum % difference between long+short and collateralPerPair
* @param lsp LongShortPair for the target dominance pair
* @param longLPAmount wei of long LP tokens to redeem
* @param shortLPAmount wei of long LP tokens to redeem
* @param router Address of Uniswap, Quickswap, etc. router.
* @param USDC address of this network's USDC: denominator of pools and collateral for token.
* @param deadline timestamp beyond which tx will revert.
* @param longSignature optional EIP-712 (v,r,s) signature
* @param shortSignature optional EIP-712 (v,r,s) signature
* @param withdrawMode action to take with redeemed synths: 0 nothing, 1 redeem 50:50, 2 settle after expiry
*/
function withdraw(
FixedPoint.Unsigned calldata priceDeviation_,
LongShortPair lsp,
uint longLPAmount,
uint shortLPAmount,
IUniswapV2Router02 router,
uint deadline,
Signature calldata longSignature,
Signature calldata shortSignature,
WithdrawMode withdrawMode
) public {
IERC20 long = IERC20(lsp.longToken());
IERC20 short = IERC20(lsp.shortToken());
{ // LP tokens in scope
{ // factory in scope
IUniswapV2Factory factory = IUniswapV2Factory(router.factory());
checkSlippage(long, short, priceDeviation_, lsp, factory);
}
IUniswapV2Pair longLP;
IUniswapV2Pair shortLP;
{
IUniswapV2Factory factory = IUniswapV2Factory(router.factory());
IERC20 USDC = lsp.collateralToken(); // need to cut down stack
longLP = IUniswapV2Pair(factory.getPair(address(long), address(USDC)));
shortLP = IUniswapV2Pair(factory.getPair(address(short), address(USDC)));
}
if (hasSignature(longSignature)) {
longLP.permit(
msg.sender,
address(this),
longLPAmount,
deadline,
longSignature.v,
longSignature.r,
longSignature.s);
}
if (hasSignature(shortSignature)) {
shortLP.permit(
msg.sender,
address(this),
shortLPAmount,
deadline,
shortSignature.v,
shortSignature.r,
shortSignature.s);
}
shortLP.approve(address(router), shortLPAmount);
longLP.approve(address(router), longLPAmount);
IERC20(address(longLP)).safeTransferFrom(msg.sender, address(this), longLPAmount);
IERC20(address(shortLP)).safeTransferFrom(msg.sender, address(this), shortLPAmount);
}
{
IERC20 USDC = lsp.collateralToken();
address sender = withdrawMode == WithdrawMode.Basic ? msg.sender : address(this);
router.removeLiquidity(
address(long),
address(USDC),
longLPAmount,
0,
0,
sender,
deadline
);
router.removeLiquidity(
address(short),
address(USDC),
shortLPAmount,
0,
0,
sender,
deadline
);
if (withdrawMode == WithdrawMode.Redeem) {
uint synthToRedeem = long.balanceOf(address(this)) > short.balanceOf(address(this))
? short.balanceOf(address(this))
: long.balanceOf(address(this));
lsp.redeem(synthToRedeem);
USDC.safeTransfer(msg.sender, USDC.balanceOf(address(this)));
long.safeTransfer(msg.sender, long.balanceOf(address(this)));
short.safeTransfer(msg.sender, short.balanceOf(address(this)));
} else if (withdrawMode == WithdrawMode.Settle) {
lsp.settle(long.balanceOf(address(this)), short.balanceOf(address(this)));
USDC.safeTransfer(msg.sender, USDC.balanceOf(address(this)));
}
}
}
/**
* @notice Arb a pair's pools: use supplied USDC to mint+sell or buy+redeem. Return USDC + profits to sender.
* @dev compute optimal arb amount off-chain
* @param amount USDC to use for arbitrage
* @param tokensToBuy Number of tokens to buy and redeem. If 0, mint and sell with supplied USDC
* @param lsp LongShortPair for the target dominance pair
* @param router Address of Uniswap, Quickswap, etc. router.
* @param deadline Timestamp beyond which tx will revert.
* @param usdcSignature optional signature
*/
function arbitrage(
uint amount,
uint tokensToBuy,
LongShortPair lsp,
IUniswapV2Router02 router,
uint deadline,
Signature calldata usdcSignature
) external {
IUSDC USDC = IUSDC(address(lsp.collateralToken()));
if (hasSignature(usdcSignature)) {
USDC.permit(msg.sender, address(this), amount, deadline, usdcSignature.v, usdcSignature.r, usdcSignature.s);
}
USDC.safeTransferFrom(msg.sender, address(this), amount);
_arbitrage(amount, tokensToBuy, lsp, router, deadline);
USDC.safeTransfer(msg.sender, USDC.balanceOf(address(this)));
}
/**
* @notice Arb a pair's pools: use supplied USDC to mint+sell or buy+redeem.
* @dev compute optimal arb amount off-chain
* @dev precondition: vault has USDC bal >= usdcToUse
* @param usdcToUse USDC to use for arbitrage
* @param tokensToBuy Number of tokens to buy and redeem. If 0, mint and sell with supplied USDC
* @param lsp LongShortPair for the target dominance pair
* @param router Address of Uniswap, Quickswap, etc. router.
* @param deadline Timestamp beyond which tx will revert.
*/
function _arbitrage(
uint usdcToUse,
uint tokensToBuy,
LongShortPair lsp,
IUniswapV2Router02 router,
uint deadline
) internal {
require(usdcToUse > 0, "INVALID ARGUMENTS"); // must have some amount of USDC to work with
IUSDC USDC = IUSDC(address(lsp.collateralToken()));
IERC20 long = lsp.longToken();
IERC20 short = lsp.shortToken();
uint startUSDCbal = USDC.balanceOf(address(this));
if (tokensToBuy > 0) { // buy and redeem equal amounts of token with the supplied USDC
USDC.approve(address(router), usdcToUse);
address[] memory path = new address[](2); // can't cast static array to dynamic >:(
path[0] = address(USDC);
path[1] = address(long);
router.swapTokensForExactTokens(
tokensToBuy,
usdcToUse,
path,
address(this),
deadline
);
path[1] = address(short);
router.swapTokensForExactTokens(
tokensToBuy,
usdcToUse,
path,
address(this),
deadline
);
long.approve(address(lsp), tokensToBuy);
short.approve(address(lsp), tokensToBuy);
lsp.redeem(tokensToBuy);
} else { // mint tokens with usdcToUse and sell them all
USDC.approve(address(lsp), usdcToUse);
uint tokensToMint = usdcToUse / (lsp.collateralPerPair() / FixedPoint.fromUnscaledUint(1).rawValue);
lsp.create(tokensToMint);
long.approve(address(router), tokensToMint);
short.approve(address(router), tokensToMint);
address[] memory path = new address[](2);
path[1] = address(USDC);
path[0] = address(long);
router.swapExactTokensForTokens(
tokensToMint,
0,
path,
address(this),
deadline
);
path[0] = address(short);
router.swapExactTokensForTokens(
tokensToMint,
0,
path,
address(this),
deadline
);
}
// We could check price deviation, but that requires more complicated parameters and more gas. If you need to
// arbitrage pools very precisely, increase gas for a fast transaction or write your own contract.
uint USDCbal = USDC.balanceOf(address(this));
require(USDCbal > startUSDCbal, "UNPROFITABLE"); // arbing in the right direction makes money
}
/**
* @notice Check the market value of a user's LSP liquidity, in USDC.
*/
function depositedFor(
IUniswapV2Factory factory,
LongShortPair lsp,
IERC900 longStaking,
IERC900 shortStaking,
address user
) public view returns (uint) {
IERC20 USDC = lsp.collateralToken();
IERC20 longPool = IERC20(factory.getPair(address(lsp.longToken()), address(USDC)));
IERC20 shortPool = IERC20(factory.getPair(address(lsp.shortToken()), address(USDC)));
uint longUSDC = USDC.balanceOf(address(longPool));
uint shortUSDC = USDC.balanceOf(address(shortPool));
FixedPoint.Unsigned memory longShare =
FixedPoint.fromUnscaledUint(longPool.balanceOf(user))
.add(address(longStaking) != address(0)
? longStaking.totalStakedFor(user)
: 0)
.div(longPool.totalSupply());
FixedPoint.Unsigned memory shortShare =
FixedPoint.fromUnscaledUint(shortPool.balanceOf(user))
.add(address(shortStaking) != address(0)
? shortStaking.totalStakedFor(user)
: 0)
.div(shortPool.totalSupply());
return longShare.mul(FixedPoint.Unsigned(longUSDC))
.add(shortShare.mul(FixedPoint.Unsigned(shortUSDC)))
.mul(2)
.rawValue;
}
function computeLPAmounts(
IUniswapV2Router02 router,
FixedPoint.Unsigned calldata priceDeviation_,
LongShortPair lsp,
uint amount
) internal view returns (
uint tokensToMint,
uint mintUSDC,
uint longValue,
uint shortValue
) {
IERC20 long = IERC20(lsp.longToken());
IERC20 short = IERC20(lsp.shortToken());
IUniswapV2Factory factory = IUniswapV2Factory(router.factory());
(
FixedPoint.Unsigned memory longPrice,
FixedPoint.Unsigned memory shortPrice,
FixedPoint.Unsigned memory collateralPerPair
) = checkSlippage(long, short, priceDeviation_, lsp, factory);
tokensToMint = FixedPoint.Unsigned(amount)
.div(
collateralPerPair
.add(longPrice)
.add(shortPrice)).rawValue;
mintUSDC = collateralPerPair.mul(FixedPoint.Unsigned(tokensToMint)).rawValue;
longValue = longPrice.mul(FixedPoint.Unsigned(tokensToMint)).rawValue;
shortValue = shortPrice.mul(FixedPoint.Unsigned(tokensToMint)).rawValue;
}
function checkSlippage(
IERC20 long,
IERC20 short,
FixedPoint.Unsigned calldata priceDeviation_,
LongShortPair lsp,
IUniswapV2Factory factory
) internal view returns (
FixedPoint.Unsigned memory longPrice,
FixedPoint.Unsigned memory shortPrice,
FixedPoint.Unsigned memory collateralPerPair
) {
IERC20 USDC = IERC20(lsp.collateralToken());
longPrice = getMarketPrice(long, USDC, factory);
shortPrice = getMarketPrice(short, USDC, factory);
collateralPerPair = FixedPoint.Unsigned(lsp.collateralPerPair());
require(
priceDeviation(longPrice, shortPrice, collateralPerPair).isLessThanOrEqual(priceDeviation_),
"SLIPPAGE");
}
/**
* @notice get USDC per synth market price. FixedPoint for fractional component
* @return FixedPoint.Unsigned market price ($/synth)
* @param synth token paired with USDC
* @param USDC address of this network's USDC: denominator of pools and collateral for token.
* @param factory query price for this DEX
*/
function getMarketPrice(
IERC20 synth,
IERC20 USDC,
IUniswapV2Factory factory
) internal view returns (FixedPoint.Unsigned memory) {
address pool = factory.getPair(address(synth), address(USDC));
FixedPoint.Unsigned memory USDCbal = FixedPoint.fromUnscaledUint(USDC.balanceOf(pool));
uint synthbal = synth.balanceOf(pool);
require(synthbal > 0, "No synth pooled");
return USDCbal.div(synthbal);
}
/**
* @notice The vault should never hold any tokens. This method allows anyone to withdraw a token's entire balance.
* It should be used if tokens are mistakenly sent to the contract, or if a bug causes leftover balances.
* @param token address of a ERC20
*/
function rescue(IERC20 token) external {
token.transfer(msg.sender, token.balanceOf(address(this)));
}
}

IERC900.sol

// SPDX-License-Identifier: CC0-1.0
pragma solidity 0.8.6;
/**
* @title General Staking Interface
* ERC900: https://eips.ethereum.org/EIPS/eip-900
*/
interface IERC900 {
event Staked(address indexed user, uint256 amount, uint256 total);
event Unstaked(address indexed user, uint256 amount, uint256 total);
/**
* @dev Stake a certain amount of tokens
* @param _amount Amount of tokens to be staked
*/
function stake(uint256 _amount) external;
/**
* @dev Stake a certain amount of tokens to another address
* @param _user Address to stake tokens to
* @param _amount Amount of tokens to be staked
*/
function stakeFor(address _user, uint256 _amount) external;
/**
* @dev Unstake a certain amount of tokens
* @param _amount Amount of tokens to be unstaked
*/
function unstake(uint256 _amount) external;
/**
* @dev Tell the current total amount of tokens staked for an address
* @param _addr Address to query
* @return Current total amount of tokens staked for the address
*/
function totalStakedFor(address _addr) external view returns (uint256);
/**
* @dev Tell the current total amount of tokens staked from all addresses
* @return Current total amount of tokens staked from all addresses
*/
function totalStaked() external view returns (uint256);
/**
* @dev Tell the address of the staking token
* @return Address of the staking token
*/
function stakingToken() external view returns (address);
/**
* @dev Tell the address of the reward token
* @return Address of the reward token
*/
function rewardToken() external view returns (address);
/*
* @dev Tell if the optional history functions are implemented
* - check interface at IERC900HistoryExtension
*
* @return True if the optional history functions are implemented
*/
function supportsHistory() external pure returns (bool);
}

IUSDC.sol

// SPDX-License-Identifier: MIT
pragma solidity 0.8.6;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
/** @notice Interface with USDC's permit method. From
* https://github.com/centrehq/centre-tokens/blob/master/contracts/v2/FiatTokenV2.sol
*/
interface IUSDC is IERC20 {
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
}

IUniswapV2Router02.sol

pragma solidity >=0.6.2;
import './IUniswapV2Router01.sol';
interface IUniswapV2Router02 is IUniswapV2Router01 {
function removeLiquidityETHSupportingFeeOnTransferTokens(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline
) external returns (uint amountETH);
function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline,
bool approveMax, uint8 v, bytes32 r, bytes32 s
) external returns (uint amountETH);
function swapExactTokensForTokensSupportingFeeOnTransferTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external;
function swapExactETHForTokensSupportingFeeOnTransferTokens(
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external payable;
function swapExactTokensForETHSupportingFeeOnTransferTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external;
}

IUniswapV2Router01.sol

pragma solidity >=0.6.2;
interface IUniswapV2Router01 {
function factory() external pure returns (address);
function WETH() external pure returns (address);
function addLiquidity(
address tokenA,
address tokenB,
uint amountADesired,
uint amountBDesired,
uint amountAMin,
uint amountBMin,
address to,
uint deadline
) external returns (uint amountA, uint amountB, uint liquidity);
function addLiquidityETH(
address token,
uint amountTokenDesired,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline
) external payable returns (uint amountToken, uint amountETH, uint liquidity);
function removeLiquidity(
address tokenA,
address tokenB,
uint liquidity,
uint amountAMin,
uint amountBMin,
address to,
uint deadline
) external returns (uint amountA, uint amountB);
function removeLiquidityETH(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline
) external returns (uint amountToken, uint amountETH);
function removeLiquidityWithPermit(
address tokenA,
address tokenB,
uint liquidity,
uint amountAMin,
uint amountBMin,
address to,
uint deadline,
bool approveMax, uint8 v, bytes32 r, bytes32 s
) external returns (uint amountA, uint amountB);
function removeLiquidityETHWithPermit(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline,
bool approveMax, uint8 v, bytes32 r, bytes32 s
) external returns (uint amountToken, uint amountETH);
function swapExactTokensForTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external returns (uint[] memory amounts);
function swapTokensForExactTokens(
uint amountOut,
uint amountInMax,
address[] calldata path,
address to,
uint deadline
) external returns (uint[] memory amounts);
function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline)
external
payable
returns (uint[] memory amounts);
function swapTokensForExactETH(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline)
external
returns (uint[] memory amounts);
function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline)
external
returns (uint[] memory amounts);
function swapETHForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline)
external
payable
returns (uint[] memory amounts);
function quote(uint amountA, uint reserveA, uint reserveB) external pure returns (uint amountB);
function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) external pure returns (uint amountOut);
function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) external pure returns (uint amountIn);
function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts);
function getAmountsIn(uint amountOut, address[] calldata path) external view returns (uint[] memory amounts);
}

IUniswapV2Pair.sol

pragma solidity >=0.5.0;
interface IUniswapV2Pair {
event Approval(address indexed owner, address indexed spender, uint value);
event Transfer(address indexed from, address indexed to, uint value);
function name() external pure returns (string memory);
function symbol() external pure returns (string memory);
function decimals() external pure returns (uint8);
function totalSupply() external view returns (uint);
function balanceOf(address owner) external view returns (uint);
function allowance(address owner, address spender) external view returns (uint);
function approve(address spender, uint value) external returns (bool);
function transfer(address to, uint value) external returns (bool);
function transferFrom(address from, address to, uint value) external returns (bool);
function DOMAIN_SEPARATOR() external view returns (bytes32);
function PERMIT_TYPEHASH() external pure returns (bytes32);
function nonces(address owner) external view returns (uint);
function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external;
event Mint(address indexed sender, uint amount0, uint amount1);
event Burn(address indexed sender, uint amount0, uint amount1, address indexed to);
event Swap(
address indexed sender,
uint amount0In,
uint amount1In,
uint amount0Out,
uint amount1Out,
address indexed to
);
event Sync(uint112 reserve0, uint112 reserve1);
function MINIMUM_LIQUIDITY() external pure returns (uint);
function factory() external view returns (address);
function token0() external view returns (address);
function token1() external view returns (address);
function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);
function price0CumulativeLast() external view returns (uint);
function price1CumulativeLast() external view returns (uint);
function kLast() external view returns (uint);
function mint(address to) external returns (uint liquidity);
function burn(address to) external returns (uint amount0, uint amount1);
function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external;
function skim(address to) external;
function sync() external;
function initialize(address, address) external;
}

IUniswapV2Factory.sol

pragma solidity >=0.5.0;
interface IUniswapV2Factory {
event PairCreated(address indexed token0, address indexed token1, address pair, uint);
function feeTo() external view returns (address);
function feeToSetter() external view returns (address);
function getPair(address tokenA, address tokenB) external view returns (address pair);
function allPairs(uint) external view returns (address pair);
function allPairsLength() external view returns (uint);
function createPair(address tokenA, address tokenB) external returns (address pair);
function setFeeTo(address) external;
function setFeeToSetter(address) external;
}

OracleInterface.sol

// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.0;
/**
* @title Financial contract facing Oracle interface.
* @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.
*/
abstract contract OracleInterface {
/**
* @notice Enqueues a request (if a request isn't already present) for the given `identifier`, `time` pair.
* @dev Time must be in the past and the identifier must be supported.
* @param identifier uniquely identifies the price requested. eg BTC/USD (encoded as bytes32) could be requested.
* @param time unix timestamp for the price request.
*/
function requestPrice(bytes32 identifier, uint256 time) public virtual;
/**
* @notice Whether the price for `identifier` and `time` is available.
* @dev Time must be in the past and the identifier must be supported.
* @param identifier uniquely identifies the price requested. eg BTC/USD (encoded as bytes32) could be requested.
* @param time unix timestamp for the price request.
* @return bool if the DVM has resolved to a price for the given identifier and timestamp.
*/
function hasPrice(bytes32 identifier, uint256 time) public view virtual returns (bool);
/**
* @notice Gets the price for `identifier` and `time` if it has already been requested and resolved.
* @dev If the price is not available, the method reverts.
* @param identifier uniquely identifies the price requested. eg BTC/USD (encoded as bytes32) could be requested.
* @param time unix timestamp for the price request.
* @return int256 representing the resolved price for the given identifier and timestamp.
*/
function getPrice(bytes32 identifier, uint256 time) public view virtual returns (int256);
}

OptimisticOracleInterface.sol

// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
/**
* @title Financial contract facing Oracle interface.
* @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.
*/
abstract contract OptimisticOracleInterface {
// Struct representing the state of a price request.
enum State {
Invalid, // Never requested.
Requested, // Requested, no other actions taken.
Proposed, // Proposed, but not expired or disputed yet.
Expired, // Proposed, not disputed, past liveness.
Disputed, // Disputed, but no DVM price returned yet.
Resolved, // Disputed and DVM price is available.
Settled // Final price has been set in the contract (can get here from Expired or Resolved).
}
// Struct representing a price request.
struct Request {
address proposer; // Address of the proposer.
address disputer; // Address of the disputer.
IERC20 currency; // ERC20 token used to pay rewards and fees.
bool settled; // True if the request is settled.
bool refundOnDispute; // True if the requester should be refunded their reward on dispute.
int256 proposedPrice; // Price that the proposer submitted.
int256 resolvedPrice; // Price resolved once the request is settled.
uint256 expirationTime; // Time at which the request auto-settles without a dispute.
uint256 reward; // Amount of the currency to pay to the proposer on settlement.
uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.
uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.
uint256 customLiveness; // Custom liveness value set by the requester.
}
// This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible
// that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses
// to accept a price request made with ancillary data length over a certain size.
uint256 public constant ancillaryBytesLimit = 8192;
/**
* @notice Requests a new price.
* @param identifier price identifier being requested.
* @param timestamp timestamp of the price being requested.
* @param ancillaryData ancillary data representing additional args being passed with the price request.
* @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.
* @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,
* which could make sense if the contract requests and proposes the value in the same call or
* provides its own reward system.
* @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.
* This can be changed with a subsequent call to setBond().
*/
function requestPrice(
bytes32 identifier,
uint256 timestamp,
bytes memory ancillaryData,
IERC20 currency,
uint256 reward
) external virtual returns (uint256 totalBond);
/**
* @notice Set the proposal bond associated with a price request.
* @param identifier price identifier to identify the existing request.
* @param timestamp timestamp to identify the existing request.
* @param ancillaryData ancillary data of the price being requested.
* @param bond custom bond amount to set.
* @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be
* changed again with a subsequent call to setBond().
*/
function setBond(
bytes32 identifier,
uint256 timestamp,
bytes memory ancillaryData,
uint256 bond
) external virtual returns (uint256 totalBond);
/**
* @notice Sets the request to refund the reward if the proposal is disputed. This can help to "hedge" the caller
* in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's
* bond, so there is still profit to be made even if the reward is refunded.
* @param identifier price identifier to identify the existing request.
* @param timestamp timestamp to identify the existing request.
* @param ancillaryData ancillary data of the price being requested.
*/
function setRefundOnDispute(
bytes32 identifier,
uint256 timestamp,
bytes memory ancillaryData
) external virtual;
/**
* @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before
* being auto-resolved.
* @param identifier price identifier to identify the existing request.
* @param timestamp timestamp to identify the existing request.
* @param ancillaryData ancillary data of the price being requested.
* @param customLiveness new custom liveness.
*/
function setCustomLiveness(
bytes32 identifier,
uint256 timestamp,
bytes memory ancillaryData,
uint256 customLiveness
) external virtual;
/**
* @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come
* from this proposal. However, any bonds are pulled from the caller.
* @param proposer address to set as the proposer.
* @param requester sender of the initial price request.
* @param identifier price identifier to identify the existing request.
* @param timestamp timestamp to identify the existing request.
* @param ancillaryData ancillary data of the price being requested.
* @param proposedPrice price being proposed.
* @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to
* the proposer once settled if the proposal is correct.
*/
function proposePriceFor(
address proposer,
address requester,
bytes32 identifier,
uint256 timestamp,
bytes memory ancillaryData,
int256 proposedPrice
) public virtual returns (uint256 totalBond);
/**
* @notice Proposes a price value for an existing price request.
* @param requester sender of the initial price request.
* @param identifier price identifier to identify the existing request.
* @param timestamp timestamp to identify the existing request.
* @param ancillaryData ancillary data of the price being requested.
* @param proposedPrice price being proposed.
* @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to
* the proposer once settled if the proposal is correct.
*/
function proposePrice(
address requester,
bytes32 identifier,
uint256 timestamp,
bytes memory ancillaryData,
int256 proposedPrice
) external virtual returns (uint256 totalBond);
/**
* @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will
* receive any rewards that come from this dispute. However, any bonds are pulled from the caller.
* @param disputer address to set as the disputer.
* @param requester sender of the initial price request.
* @param identifier price identifier to identify the existing request.
* @param timestamp timestamp to identify the existing request.
* @param ancillaryData ancillary data of the price being requested.
* @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to
* the disputer once settled if the dispute was value (the proposal was incorrect).
*/
function disputePriceFor(
address disputer,
address requester,
bytes32 identifier,
uint256 timestamp,
bytes memory ancillaryData
) public virtual returns (uint256 totalBond);
/**
* @notice Disputes a price value for an existing price request with an active proposal.
* @param requester sender of the initial price request.
* @param identifier price identifier to identify the existing request.
* @param timestamp timestamp to identify the existing request.
* @param ancillaryData ancillary data of the price being requested.
* @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to
* the disputer once settled if the dispute was valid (the proposal was incorrect).
*/
function disputePrice(
address requester,
bytes32 identifier,
uint256 timestamp,
bytes memory ancillaryData
) external virtual returns (uint256 totalBond);
/**
* @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled
* or settleable. Note: this method is not view so that this call may actually settle the price request if it
* hasn't been settled.
* @param identifier price identifier to identify the existing request.
* @param timestamp timestamp to identify the existing request.
* @param ancillaryData ancillary data of the price being requested.
* @return resolved price.
*/
function settleAndGetPrice(
bytes32 identifier,
uint256 timestamp,
bytes memory ancillaryData
) external virtual returns (int256);
/**
* @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.
* @param requester sender of the initial price request.
* @param identifier price identifier to identify the existing request.
* @param timestamp timestamp to identify the existing request.
* @param ancillaryData ancillary data of the price being requested.
* @return payout the amount that the "winner" (proposer or disputer) receives on settlement. This amount includes
* the returned bonds as well as additional rewards.
*/
function settle(
address requester,
bytes32 identifier,
uint256 timestamp,
bytes memory ancillaryData
) external virtual returns (uint256 payout);
/**
* @notice Gets the current data structure containing all information about a price request.
* @param requester sender of the initial price request.
* @param identifier price identifier to identify the existing request.
* @param timestamp timestamp to identify the existing request.
* @param ancillaryData ancillary data of the price being requested.
* @return the Request data structure.
*/
function getRequest(
address requester,
bytes32 identifier,
uint256 timestamp,
bytes memory ancillaryData
) public view virtual returns (Request memory);
/**
* @notice Returns the state of a price request.
* @param requester sender of the initial price request.
* @param identifier price identifier to identify the existing request.
* @param timestamp timestamp to identify the existing request.
* @param ancillaryData ancillary data of the price being requested.
* @return the State enum value.
*/
function getState(
address requester,
bytes32 identifier,
uint256 timestamp,
bytes memory ancillaryData
) public view virtual returns (State);
/**
* @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).
* @param requester sender of the initial price request.
* @param identifier price identifier to identify the existing request.
* @param timestamp timestamp to identify the existing request.
* @param ancillaryData ancillary data of the price being requested.
* @return true if price has resolved or settled, false otherwise.
*/
function hasPrice(
address requester,
bytes32 identifier,
uint256 timestamp,
bytes memory ancillaryData
) public view virtual returns (bool);
function stampAncillaryData(bytes memory ancillaryData, address requester)
public
view
virtual
returns (bytes memory);
}

IdentifierWhitelistInterface.sol

// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.0;
/**
* @title Interface for whitelists of supported identifiers that the oracle can provide prices for.
*/
interface IdentifierWhitelistInterface {
/**
* @notice Adds the provided identifier as a supported identifier.
* @dev Price requests using this identifier will succeed after this call.
* @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.
*/
function addSupportedIdentifier(bytes32 identifier) external;
/**
* @notice Removes the identifier from the whitelist.
* @dev Price requests using this identifier will no longer succeed after this call.
* @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.
*/
function removeSupportedIdentifier(bytes32 identifier) external;
/**
* @notice Checks whether an identifier is on the whitelist.
* @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.
* @return bool if the identifier is supported (or not).
*/
function isIdentifierSupported(bytes32 identifier) external view returns (bool);
}

FinderInterface.sol

// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.0;
/**
* @title Provides addresses of the live contracts implementing certain interfaces.
* @dev Examples are the Oracle or Store interfaces.
*/
interface FinderInterface {
/**
* @notice Updates the address of the contract that implements `interfaceName`.
* @param interfaceName bytes32 encoding of the interface name that is either changed or registered.
* @param implementationAddress address of the deployed contract that implements the interface.
*/
function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;
/**
* @notice Gets the address of the contract that implements the given `interfaceName`.
* @param interfaceName queried interface.
* @return implementationAddress address of the deployed contract that implements the interface.
*/
function getImplementationAddress(bytes32 interfaceName) external view returns (address);
}

Constants.sol

// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.0;
/**
* @title Stores common interface names used throughout the DVM by registration in the Finder.
*/
library OracleInterfaces {
bytes32 public constant Oracle = "Oracle";
bytes32 public constant IdentifierWhitelist = "IdentifierWhitelist";
bytes32 public constant Store = "Store";
bytes32 public constant FinancialContractsAdmin = "FinancialContractsAdmin";
bytes32 public constant Registry = "Registry";
bytes32 public constant CollateralWhitelist = "CollateralWhitelist";
bytes32 public constant OptimisticOracle = "OptimisticOracle";
bytes32 public constant Bridge = "Bridge";
bytes32 public constant GenericHandler = "GenericHandler";
bytes32 public constant SkinnyOptimisticOracle = "SkinnyOptimisticOracle";
}
/**
* @title Commonly re-used values for contracts associated with the OptimisticOracle.
*/
library OptimisticOracleConstraints {
// Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.
// This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible
// that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which
// refuses to accept a price request made with ancillary data length over a certain size.
uint256 public constant ancillaryBytesLimit = 8192;
}

LongShortPair.sol

// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/utils/math/Math.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "../common/financial-product-libraries/long-short-pair-libraries/LongShortPairFinancialProductLibrary.sol";
import "../../common/implementation/AncillaryData.sol";
import "../../common/implementation/Testable.sol";
import "../../common/implementation/Lockable.sol";
import "../../common/implementation/FixedPoint.sol";
import "../../common/interfaces/ExpandedIERC20.sol";
import "../../oracle/interfaces/OracleInterface.sol";
import "../../common/interfaces/AddressWhitelistInterface.sol";
import "../../oracle/interfaces/FinderInterface.sol";
import "../../oracle/interfaces/OptimisticOracleInterface.sol";
import "../../oracle/interfaces/IdentifierWhitelistInterface.sol";
import "../../oracle/implementation/Constants.sol";
/**
* @title Long Short Pair.
* @notice Uses a combination of long and short tokens to tokenize the bounded price exposure to a given identifier.
*/
contract LongShortPair is Testable, Lockable {
using FixedPoint for FixedPoint.Unsigned;
using SafeERC20 for IERC20;
/*************************************
* LONG SHORT PAIR DATA STRUCTURES *
*************************************/
// Define the contract's constructor parameters as a struct to enable more variables to be specified.
struct ConstructorParams {
string pairName; // Name of the long short pair contract.
uint64 expirationTimestamp; // Unix timestamp of when the contract will expire.
uint256 collateralPerPair; // How many units of collateral are required to mint one pair of synthetic tokens.
bytes32 priceIdentifier; // Price identifier, registered in the DVM for the long short pair.
bool enableEarlyExpiration; // Enables the LSP contract to be settled early.
ExpandedIERC20 longToken; // Token used as long in the LSP. Mint and burn rights needed by this contract.
ExpandedIERC20 shortToken; // Token used as short in the LSP. Mint and burn rights needed by this contract.
IERC20 collateralToken; // Collateral token used to back LSP synthetics.
LongShortPairFinancialProductLibrary financialProductLibrary; // Contract providing settlement payout logic.
bytes customAncillaryData; // Custom ancillary data to be passed along with the price request to the OO.
uint256 proposerReward; // Optimistic oracle reward amount, pulled from the caller of the expire function.
uint256 optimisticOracleLivenessTime; // OO liveness time for price requests.
uint256 optimisticOracleProposerBond; // OO proposer bond for price requests.
FinderInterface finder; // DVM finder to find other UMA ecosystem contracts.
address timerAddress; // Timer used to synchronize contract time in testing. Set to 0x000... in production.
}
bool public receivedSettlementPrice;
bool public enableEarlyExpiration; // If set, the LSP contract can request to be settled early by calling the OO.
uint64 public expirationTimestamp;
uint64 public earlyExpirationTimestamp; // Set in the case the contract is expired early.
string public pairName;
uint256 public collateralPerPair; // Amount of collateral a pair of tokens is always redeemable for.
// Number between 0 and 1e18 to allocate collateral between long & short tokens at redemption. 0 entitles each short
// to collateralPerPair and each long to 0. 1e18 makes each long worth collateralPerPair and short 0.
uint256 public expiryPercentLong;
bytes32 public priceIdentifier;
// Price returned from the Optimistic oracle at settlement time.
int256 public expiryPrice;
// External contract interfaces.
IERC20 public collateralToken;
ExpandedIERC20 public longToken;
ExpandedIERC20 public shortToken;
FinderInterface public finder;
LongShortPairFinancialProductLibrary public financialProductLibrary;
// Optimistic oracle customization parameters.
bytes public customAncillaryData;
uint256 public proposerReward;
uint256 public optimisticOracleLivenessTime;
uint256 public optimisticOracleProposerBond;
/****************************************
* EVENTS *
****************************************/
event TokensCreated(address indexed sponsor, uint256 indexed collateralUsed, uint256 indexed tokensMinted);
event TokensRedeemed(address indexed sponsor, uint256 indexed collateralReturned, uint256 indexed tokensRedeemed);
event ContractExpired(address indexed caller);
event EarlyExpirationRequested(address indexed caller, uint64 earlyExpirationTimeStamp);
event PositionSettled(address indexed sponsor, uint256 collateralReturned, uint256 longTokens, uint256 shortTokens);
/****************************************
* MODIFIERS *
****************************************/
modifier preExpiration() {
require(getCurrentTime() < expirationTimestamp, "Only callable pre-expiry");
_;
}
modifier postExpiration() {
require(getCurrentTime() >= expirationTimestamp, "Only callable post-expiry");
_;
}
modifier notEarlyExpired() {
require(!isContractEarlyExpired(), "Contract already early expired");
_;
}
/**
* @notice Construct the LongShortPair
* @param params Constructor params used to initialize the LSP. Key-valued object with the following structure:
* - `pairName`: Name of the long short pair contract.
* - `expirationTimestamp`: Unix timestamp of when the contract will expire.
* - `collateralPerPair`: How many units of collateral are required to mint one pair of synthetic tokens.
* - `priceIdentifier`: Price identifier, registered in the DVM for the long short pair.
* - `longToken`: Token used as long in the LSP. Mint and burn rights needed by this contract.
* - `shortToken`: Token used as short in the LSP. Mint and burn rights needed by this contract.
* - `collateralToken`: Collateral token used to back LSP synthetics.
* - `financialProductLibrary`: Contract providing settlement payout logic.
* - `customAncillaryData`: Custom ancillary data to be passed along with the price request to the OO.
* - `proposerReward`: Preloaded reward to incentivize settlement price proposals.
* - `optimisticOracleLivenessTime`: OO liveness time for price requests.
* - `optimisticOracleProposerBond`: OO proposer bond for price requests.
* - `finder`: DVM finder to find other UMA ecosystem contracts.
* - `timerAddress`: Timer used to synchronize contract time in testing. Set to 0x000... in production.
*/
constructor(ConstructorParams memory params) Testable(params.timerAddress) {
finder = params.finder;
require(bytes(params.pairName).length > 0, "Pair name cant be empty");
require(params.expirationTimestamp > getCurrentTime(), "Expiration timestamp in past");
require(params.collateralPerPair > 0, "Collateral per pair cannot be 0");
require(_getIdentifierWhitelist().isIdentifierSupported(params.priceIdentifier), "Identifier not registered");
require(address(_getOptimisticOracle()) != address(0), "Invalid finder");
require(address(params.financialProductLibrary) != address(0), "Invalid FinancialProductLibrary");
require(_getCollateralWhitelist().isOnWhitelist(address(params.collateralToken)), "Collateral not whitelisted");
require(params.optimisticOracleLivenessTime > 0, "OO liveness cannot be 0");
require(params.optimisticOracleLivenessTime < 5200 weeks, "OO liveness too large");
pairName = params.pairName;
expirationTimestamp = params.expirationTimestamp;
collateralPerPair = params.collateralPerPair;
priceIdentifier = params.priceIdentifier;
enableEarlyExpiration = params.enableEarlyExpiration;
longToken = params.longToken;
shortToken = params.shortToken;
collateralToken = params.collateralToken;
financialProductLibrary = params.financialProductLibrary;
OptimisticOracleInterface optimisticOracle = _getOptimisticOracle();
// Ancillary data + additional stamped information should be less than ancillary data limit. Consider early
// expiration ancillary data, if enableEarlyExpiration is set.
customAncillaryData = params.customAncillaryData;
require(
optimisticOracle
.stampAncillaryData(
(enableEarlyExpiration ? getEarlyExpirationAncillaryData() : customAncillaryData),
address(this)
)
.length <= optimisticOracle.ancillaryBytesLimit(),
"Ancillary Data too long"
);
proposerReward = params.proposerReward;
optimisticOracleLivenessTime = params.optimisticOracleLivenessTime;
optimisticOracleProposerBond = params.optimisticOracleProposerBond;
}
/****************************************
* POSITION FUNCTIONS *
****************************************/
/**
* @notice Creates a pair of long and short tokens equal in number to tokensToCreate. Pulls the required collateral
* amount into this contract, defined by the collateralPerPair value.
* @dev The caller must approve this contract to transfer `tokensToCreate * collateralPerPair` amount of collateral.
* @param tokensToCreate number of long and short synthetic tokens to create.
* @return collateralUsed total collateral used to mint the synthetics.
*/
function create(uint256 tokensToCreate) public preExpiration() nonReentrant() returns (uint256 collateralUsed) {
// Note the use of mulCeil to prevent small collateralPerPair causing rounding of collateralUsed to 0 enabling
// callers to mint dust LSP tokens without paying any collateral.
collateralUsed = FixedPoint.Unsigned(tokensToCreate).mulCeil(FixedPoint.Unsigned(collateralPerPair)).rawValue;
collateralToken.safeTransferFrom(msg.sender, address(this), collateralUsed);
require(longToken.mint(msg.sender, tokensToCreate));
require(shortToken.mint(msg.sender, tokensToCreate));
emit TokensCreated(msg.sender, collateralUsed, tokensToCreate);
}
/**
* @notice Redeems a pair of long and short tokens equal in number to tokensToRedeem. Returns the commensurate
* amount of collateral to the caller for the pair of tokens, defined by the collateralPerPair value.
* @dev This contract must have the `Burner` role for the `longToken` and `shortToken` in order to call `burnFrom`.
* @dev The caller does not need to approve this contract to transfer any amount of `tokensToRedeem` since long
* and short tokens are burned, rather than transferred, from the caller.
* @dev This method can be called either pre or post expiration.
* @param tokensToRedeem number of long and short synthetic tokens to redeem.
* @return collateralReturned total collateral returned in exchange for the pair of synthetics.
*/
function redeem(uint256 tokensToRedeem) public nonReentrant() returns (uint256 collateralReturned) {
require(longToken.burnFrom(msg.sender, tokensToRedeem));
require(shortToken.burnFrom(msg.sender, tokensToRedeem));
collateralReturned = FixedPoint.Unsigned(tokensToRedeem).mul(FixedPoint.Unsigned(collateralPerPair)).rawValue;
collateralToken.safeTransfer(msg.sender, collateralReturned);
emit TokensRedeemed(msg.sender, collateralReturned, tokensToRedeem);
}
/**
* @notice Settle long and/or short tokens in for collateral at a rate informed by the contract settlement.
* @dev Uses financialProductLibrary to compute the redemption rate between long and short tokens.
* @dev This contract must have the `Burner` role for the `longToken` and `shortToken` in order to call `burnFrom`.
* @dev The caller does not need to approve this contract to transfer any amount of `tokensToRedeem` since long
* and short tokens are burned, rather than transferred, from the caller.
* @dev This function can be called before or after expiration to facilitate early expiration. If a price has
* not yet been resolved for either normal or early expiration yet then it will revert.
* @param longTokensToRedeem number of long tokens to settle.
* @param shortTokensToRedeem number of short tokens to settle.
* @return collateralReturned total collateral returned in exchange for the pair of synthetics.
*/
function settle(uint256 longTokensToRedeem, uint256 shortTokensToRedeem)
public
nonReentrant()
returns (uint256 collateralReturned)
{
// Either early expiration is enabled and it's before the expiration time or it's after the expiration time.
require(
(enableEarlyExpiration && getCurrentTime() < expirationTimestamp) ||
getCurrentTime() >= expirationTimestamp,
"Cannot settle"
);
// Get the settlement price and store it. Also sets expiryPercentLong to inform settlement. Reverts if either:
// a) the price request has not resolved (either a normal expiration call or early expiration call) or b) If the
// the contract was attempted to be settled early but the price returned is the ignore oracle price.
// Note that we use the bool receivedSettlementPrice over checking for price != 0 as 0 is a valid price.
if (!receivedSettlementPrice) getExpirationPrice();
require(longToken.burnFrom(msg.sender, longTokensToRedeem));
require(shortToken.burnFrom(msg.sender, shortTokensToRedeem));
// expiryPercentLong is a number between 0 and 1e18. 0 means all collateral goes to short tokens and 1e18 means
// all collateral goes to the long token. Total collateral returned is the sum of payouts.
uint256 longCollateralRedeemed =
FixedPoint
.Unsigned(longTokensToRedeem)
.mul(FixedPoint.Unsigned(collateralPerPair))
.mul(FixedPoint.Unsigned(expiryPercentLong))
.rawValue;
uint256 shortCollateralRedeemed =
FixedPoint
.Unsigned(shortTokensToRedeem)
.mul(FixedPoint.Unsigned(collateralPerPair))
.mul(FixedPoint.fromUnscaledUint(1).sub(FixedPoint.Unsigned(expiryPercentLong)))
.rawValue;
collateralReturned = longCollateralRedeemed + shortCollateralRedeemed;
collateralToken.safeTransfer(msg.sender, collateralReturned);
emit PositionSettled(msg.sender, collateralReturned, longTokensToRedeem, shortTokensToRedeem);
}
/****************************************
* GLOBAL STATE FUNCTIONS *
****************************************/
/**
* @notice Enables the LSP to request early expiration. This initiates a price request to the optimistic oracle at
* the provided timestamp with a modified version of the ancillary data that includes the key "earlyExpiration:1"
* which signals to the OO that this is an early expiration request, rather than standard settlement.
* @dev The caller must approve this contract to transfer `proposerReward` amount of collateral.
* @dev Will revert if: a) the contract is already early expired, b) it is after the expiration timestamp, c)
* early expiration is disabled for this contract, d) the proposed expiration timestamp is in the future.
* e) an early expiration attempt has already been made (in pending state).
* @param _earlyExpirationTimestamp timestamp at which the early expiration is proposed.
*/
function requestEarlyExpiration(uint64 _earlyExpirationTimestamp)
public
nonReentrant()
notEarlyExpired()
preExpiration()
{
require(enableEarlyExpiration, "Early expiration disabled");
require(_earlyExpirationTimestamp <= getCurrentTime(), "Only propose expire in the past");
require(_earlyExpirationTimestamp > 0, "Early expiration can't be 0");
earlyExpirationTimestamp = _earlyExpirationTimestamp;
_requestOraclePrice(earlyExpirationTimestamp, getEarlyExpirationAncillaryData());
emit EarlyExpirationRequested(msg.sender, _earlyExpirationTimestamp);
}
/**
* @notice Expire the LSP contract. Makes a request to the optimistic oracle to inform the settlement price.
* @dev The caller must approve this contract to transfer `proposerReward` amount of collateral.
* @dev Will revert if: a) the contract is already early expired, b) it is before the expiration timestamp or c)
* an expire call has already been made.
*/
function expire() public nonReentrant() notEarlyExpired() postExpiration() {
_requestOraclePrice(expirationTimestamp, customAncillaryData);
emit ContractExpired(msg.sender);
}
/***********************************
* GLOBAL VIEW FUNCTIONS *
***********************************/
/**
* @notice Returns the number of long and short tokens a sponsor wallet holds.
* @param sponsor address of the sponsor to query.
* @return longTokens the number of long tokens held by the sponsor.
* @return shortTokens the number of short tokens held by the sponsor.
*/
function getPositionTokens(address sponsor)
public
view
nonReentrantView()
returns (uint256 longTokens, uint256 shortTokens)
{
return (longToken.balanceOf(sponsor), shortToken.balanceOf(sponsor));
}
/**
* @notice Generates a modified ancillary data that indicates the contract is being expired early.
*/
function getEarlyExpirationAncillaryData() public view returns (bytes memory) {
return AncillaryData.appendKeyValueUint(customAncillaryData, "earlyExpiration", 1);
}
/**
* @notice Defines a special number that, if returned during an attempted early expiration, will cause the contract
* to do nothing and not expire. This enables the OO (and DVM voters in the case of a dispute) to choose to keep
* the contract running, thereby denying the early settlement request.
*/
function ignoreEarlyExpirationPrice() public pure returns (int256) {
return type(int256).min;
}
/**
* @notice If the earlyExpirationTimestamp is != 0 then a previous early expiration OO request might still be in the
* pending state. Check if the OO contains the ignore early price. If it does not contain this then the contract
* was early expired correctly. Note that _getOraclePrice call will revert if the price request is still pending,
* thereby reverting all upstream calls pre-settlement of the early expiration price request.
*/
function isContractEarlyExpired() public returns (bool) {
return (earlyExpirationTimestamp != 0 &&
_getOraclePrice(earlyExpirationTimestamp, getEarlyExpirationAncillaryData()) !=
ignoreEarlyExpirationPrice());
}
/****************************************
* INTERNAL FUNCTIONS *
****************************************/
// Return the oracle price for a given request timestamp and ancillary data combo.
function _getOraclePrice(uint64 requestTimestamp, bytes memory requestAncillaryData) internal returns (int256) {
return _getOptimisticOracle().settleAndGetPrice(priceIdentifier, requestTimestamp, requestAncillaryData);
}
// Request a price in the optimistic oracle for a given request timestamp and ancillary data combo. Set the bonds
// accordingly to the deployer's parameters. Will revert if re-requesting for a previously requested combo.
function _requestOraclePrice(uint64 requestTimestamp, bytes memory requestAncillaryData) internal {
OptimisticOracleInterface optimisticOracle = _getOptimisticOracle();
// If the proposer reward was set then pull it from the caller of the function.
if (proposerReward > 0) {
collateralToken.safeTransferFrom(msg.sender, address(this), proposerReward);
collateralToken.safeApprove(address(optimisticOracle), proposerReward);
}
optimisticOracle.requestPrice(
priceIdentifier,
uint256(requestTimestamp),
requestAncillaryData,
collateralToken,
proposerReward
);
// Set the Optimistic oracle liveness for the price request.
optimisticOracle.setCustomLiveness(
priceIdentifier,
uint256(requestTimestamp),
requestAncillaryData,
optimisticOracleLivenessTime
);
// Set the Optimistic oracle proposer bond for the price request.
optimisticOracle.setBond(
priceIdentifier,
uint256(requestTimestamp),
requestAncillaryData,
optimisticOracleProposerBond
);
}
// Fetch the optimistic oracle expiration price. If the oracle has the price for the provided expiration timestamp
// and customData combo then return this. Else, try fetch the price on the early expiration ancillary data. If
// there is no price for either, revert. If the early expiration price is the ignore price will also revert.
function getExpirationPrice() internal {
if (_getOptimisticOracle().hasPrice(address(this), priceIdentifier, expirationTimestamp, customAncillaryData))
expiryPrice = _getOraclePrice(expirationTimestamp, customAncillaryData);
else {
expiryPrice = _getOraclePrice(earlyExpirationTimestamp, getEarlyExpirationAncillaryData());
require(expiryPrice != ignoreEarlyExpirationPrice(), "Oracle prevents early expiration");
}
// Finally, compute the value of expiryPercentLong based on the expiryPrice. Cap the return value at 1e18 as
// this should, by definition, between 0 and 1e18.
expiryPercentLong = Math.min(
financialProductLibrary.percentageLongCollateralAtExpiry(expiryPrice),
FixedPoint.fromUnscaledUint(1).rawValue
);
receivedSettlementPrice = true;
}
function _getIdentifierWhitelist() internal view returns (IdentifierWhitelistInterface) {
return IdentifierWhitelistInterface(finder.getImplementationAddress(OracleInterfaces.IdentifierWhitelist));
}
function _getCollateralWhitelist() internal view returns (AddressWhitelistInterface) {
return AddressWhitelistInterface(finder.getImplementationAddress(OracleInterfaces.CollateralWhitelist));
}
function _getOptimisticOracle() internal view returns (OptimisticOracleInterface) {
return OptimisticOracleInterface(finder.getImplementationAddress(OracleInterfaces.OptimisticOracle));
}
}

LongShortPairFinancialProductLibrary.sol

// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.0;
import "../../../../common/implementation/FixedPoint.sol";
import "@openzeppelin/contracts/utils/math/SafeMath.sol";
interface ExpiringContractInterface {
function expirationTimestamp() external view returns (uint256);
}
abstract contract LongShortPairFinancialProductLibrary {
function percentageLongCollateralAtExpiry(int256 expiryPrice) public view virtual returns (uint256);
}

ExpandedIERC20.sol

// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
/**
* @title ERC20 interface that includes burn and mint methods.
*/
abstract contract ExpandedIERC20 is IERC20 {
/**
* @notice Burns a specific amount of the caller's tokens.
* @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.
*/
function burn(uint256 value) external virtual;
/**
* @dev Burns `value` tokens owned by `recipient`.
* @param recipient address to burn tokens from.
* @param value amount of tokens to burn.
*/
function burnFrom(address recipient, uint256 value) external virtual returns (bool);
/**
* @notice Mints tokens and adds them to the balance of the `to` address.
* @dev This method should be permissioned to only allow designated parties to mint tokens.
*/
function mint(address to, uint256 value) external virtual returns (bool);
function addMinter(address account) external virtual;
function addBurner(address account) external virtual;
function resetOwner(address account) external virtual;
}

AddressWhitelistInterface.sol

// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.0;
interface AddressWhitelistInterface {
function addToWhitelist(address newElement) external;
function removeFromWhitelist(address newElement) external;
function isOnWhitelist(address newElement) external view returns (bool);
function getWhitelist() external view returns (address[] memory);
}

Timer.sol

// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.0;
/**
* @title Universal store of current contract time for testing environments.
*/
contract Timer {
uint256 private currentTime;
constructor() {
currentTime = block.timestamp; // solhint-disable-line not-rely-on-time
}
/**
* @notice Sets the current time.
* @dev Will revert if not running in test mode.
* @param time timestamp to set `currentTime` to.
*/
function setCurrentTime(uint256 time) external {
currentTime = time;
}
/**
* @notice Gets the currentTime variable set in the Timer.
* @return uint256 for the current Testable timestamp.
*/
function getCurrentTime() public view returns (uint256) {
return currentTime;
}
}

Testable.sol

// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.0;
import "./Timer.sol";
/**
* @title Base class that provides time overrides, but only if being run in test mode.
*/
abstract contract Testable {
// If the contract is being run in production, then `timerAddress` will be the 0x0 address.
// Note: this variable should be set on construction and never modified.
address public timerAddress;
/**
* @notice Constructs the Testable contract. Called by child contracts.
* @param _timerAddress Contract that stores the current time in a testing environment.
* Must be set to 0x0 for production environments that use live time.
*/
constructor(address _timerAddress) {
timerAddress = _timerAddress;
}
/**
* @notice Reverts if not running in test mode.
*/
modifier onlyIfTest {
require(timerAddress != address(0x0));
_;
}
/**
* @notice Sets the current time.
* @dev Will revert if not running in test mode.
* @param time timestamp to set current Testable time to.
*/
function setCurrentTime(uint256 time) external onlyIfTest {
Timer(timerAddress).setCurrentTime(time);
}
/**
* @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode.
* Otherwise, it will return the block timestamp.
* @return uint for the current Testable timestamp.
*/
function getCurrentTime() public view virtual returns (uint256) {
if (timerAddress != address(0x0)) {
return Timer(timerAddress).getCurrentTime();
} else {
return block.timestamp; // solhint-disable-line not-rely-on-time
}
}
}

Lockable.sol

// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.0;
/**
* @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract
* is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol
* and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.
*/
contract Lockable {
bool private _notEntered;
constructor() {
// Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every
// call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full
// refund coming into effect.
_notEntered = true;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant` function is not supported. It is possible to
* prevent this from happening by making the `nonReentrant` function external, and making it call a `private`
* function that does the actual state modification.
*/
modifier nonReentrant() {
_preEntranceCheck();
_preEntranceSet();
_;
_postEntranceReset();
}
/**
* @dev Designed to prevent a view-only method from being re-entered during a call to a `nonReentrant()` state-changing method.
*/
modifier nonReentrantView() {
_preEntranceCheck();
_;
}
// Internal methods are used to avoid copying the require statement's bytecode to every `nonReentrant()` method.
// On entry into a function, `_preEntranceCheck()` should always be called to check if the function is being
// re-entered. Then, if the function modifies state, it should call `_postEntranceSet()`, perform its logic, and
// then call `_postEntranceReset()`.
// View-only methods can simply call `_preEntranceCheck()` to make sure that it is not being re-entered.
function _preEntranceCheck() internal view {
// On the first call to nonReentrant, _notEntered will be true
require(_notEntered, "ReentrancyGuard: reentrant call");
}
function _preEntranceSet() internal {
// Any calls to nonReentrant after this point will fail
_notEntered = false;
}
function _postEntranceReset() internal {
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_notEntered = true;
}
}

FixedPoint.sol

// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/utils/math/SafeMath.sol";
import "@openzeppelin/contracts/utils/math/SignedSafeMath.sol";
/**
* @title Library for fixed point arithmetic on uints
*/
library FixedPoint {
using SafeMath for uint256;
using SignedSafeMath for int256;
// Supports 18 decimals. E.g., 1e18 represents "1", 5e17 represents "0.5".
// For unsigned values:
// This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.
uint256 private constant FP_SCALING_FACTOR = 10**18;
// --------------------------------------- UNSIGNED -----------------------------------------------------------------------------
struct Unsigned {
uint256 rawValue;
}
/**
* @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.
* @param a uint to convert into a FixedPoint.
* @return the converted FixedPoint.
*/
function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {
return Unsigned(a.mul(FP_SCALING_FACTOR));
}
/**
* @notice Whether `a` is equal to `b`.
* @param a a FixedPoint.
* @param b a uint256.
* @return True if equal, or False.
*/
function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {
return a.rawValue == fromUnscaledUint(b).rawValue;
}
/**
* @notice Whether `a` is equal to `b`.
* @param a a FixedPoint.
* @param b a FixedPoint.
* @return True if equal, or False.
*/
function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {
return a.rawValue == b.rawValue;
}
/**
* @notice Whether `a` is greater than `b`.
* @param a a FixedPoint.
* @param b a FixedPoint.
* @return True if `a > b`, or False.
*/
function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {
return a.rawValue > b.rawValue;
}
/**
* @notice Whether `a` is greater than `b`.
* @param a a FixedPoint.
* @param b a uint256.
* @return True if `a > b`, or False.
*/
function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {
return a.rawValue > fromUnscaledUint(b).rawValue;
}
/**
* @notice Whether `a` is greater than `b`.
* @param a a uint256.
* @param b a FixedPoint.
* @return True if `a > b`, or False.
*/
function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {
return fromUnscaledUint(a).rawValue > b.rawValue;
}
/**
* @notice Whether `a` is greater than or equal to `b`.
* @param a a FixedPoint.
* @param b a FixedPoint.
* @return True if `a >= b`, or False.
*/
function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {
return a.rawValue >= b.rawValue;
}
/**
* @notice Whether `a` is greater than or equal to `b`.
* @param a a FixedPoint.
* @param b a uint256.
* @return True if `a >= b`, or False.
*/
function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {
return a.rawValue >= fromUnscaledUint(b).rawValue;
}
/**
* @notice Whether `a` is greater than or equal to `b`.
* @param a a uint256.
* @param b a FixedPoint.
* @return True if `a >= b`, or False.
*/
function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {
return fromUnscaledUint(a).rawValue >= b.rawValue;
}
/**
* @notice Whether `a` is less than `b`.
* @param a a FixedPoint.
* @param b a FixedPoint.
* @return True if `a < b`, or False.
*/
function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {
return a.rawValue < b.rawValue;
}
/**
* @notice Whether `a` is less than `b`.
* @param a a FixedPoint.
* @param b a uint256.
* @return True if `a < b`, or False.
*/
function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {
return a.rawValue < fromUnscaledUint(b).rawValue;
}
/**
* @notice Whether `a` is less than `b`.
* @param a a uint256.
* @param b a FixedPoint.
* @return True if `a < b`, or False.
*/
function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {
return fromUnscaledUint(a).rawValue < b.rawValue;
}
/**
* @notice Whether `a` is less than or equal to `b`.
* @param a a FixedPoint.
* @param b a FixedPoint.
* @return True if `a <= b`, or False.
*/
function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {
return a.rawValue <= b.rawValue;
}
/**
* @notice Whether `a` is less than or equal to `b`.
* @param a a FixedPoint.
* @param b a uint256.
* @return True if `a <= b`, or False.
*/
function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {
return a.rawValue <= fromUnscaledUint(b).rawValue;
}
/**
* @notice Whether `a` is less than or equal to `b`.
* @param a a uint256.
* @param b a FixedPoint.
* @return True if `a <= b`, or False.
*/
function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {
return fromUnscaledUint(a).rawValue <= b.rawValue;
}
/**
* @notice The minimum of `a` and `b`.
* @param a a FixedPoint.
* @param b a FixedPoint.
* @return the minimum of `a` and `b`.
*/
function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {
return a.rawValue < b.rawValue ? a : b;
}
/**
* @notice The maximum of `a` and `b`.
* @param a a FixedPoint.
* @param b a FixedPoint.
* @return the maximum of `a` and `b`.
*/
function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {
return a.rawValue > b.rawValue ? a : b;
}
/**
* @notice Adds two `Unsigned`s, reverting on overflow.
* @param a a FixedPoint.
* @param b a FixedPoint.
* @return the sum of `a` and `b`.
*/
function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {
return Unsigned(a.rawValue.add(b.rawValue));
}
/**
* @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.
* @param a a FixedPoint.
* @param b a uint256.
* @return the sum of `a` and `b`.
*/
function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {
return add(a, fromUnscaledUint(b));
}
/**
* @notice Subtracts two `Unsigned`s, reverting on overflow.
* @param a a FixedPoint.
* @param b a FixedPoint.
* @return the difference of `a` and `b`.
*/
function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {
return Unsigned(a.rawValue.sub(b.rawValue));
}
/**
* @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.
* @param a a FixedPoint.
* @param b a uint256.
* @return the difference of `a` and `b`.
*/
function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {
return sub(a, fromUnscaledUint(b));
}
/**
* @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.
* @param a a uint256.
* @param b a FixedPoint.
* @return the difference of `a` and `b`.
*/
function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {
return sub(fromUnscaledUint(a), b);
}
/**
* @notice Multiplies two `Unsigned`s, reverting on overflow.
* @dev This will "floor" the product.
* @param a a FixedPoint.
* @param b a FixedPoint.
* @return the product of `a` and `b`.
*/
function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {
// There are two caveats with this computation:
// 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is
// stored internally as a uint256 ~10^59.
// 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which
// would round to 3, but this computation produces the result 2.
// No need to use SafeMath because FP_SCALING_FACTOR != 0.
return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);
}
/**
* @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.
* @dev This will "floor" the product.
* @param a a FixedPoint.
* @param b a uint256.
* @return the product of `a` and `b`.
*/
function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {
return Unsigned(a.rawValue.mul(b));
}
/**
* @notice Multiplies two `Unsigned`s and "ceil's" the product, reverting on overflow.
* @param a a FixedPoint.
* @param b a FixedPoint.
* @return the product of `a` and `b`.
*/
function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {
uint256 mulRaw = a.rawValue.mul(b.rawValue);
uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;
uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);
if (mod != 0) {
return Unsigned(mulFloor.add(1));
} else {
return Unsigned(mulFloor);
}
}
/**
* @notice Multiplies an `Unsigned` and an unscaled uint256 and "ceil's" the product, reverting on overflow.
* @param a a FixedPoint.
* @param b a FixedPoint.
* @return the product of `a` and `b`.
*/
function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {
// Since b is an uint, there is no risk of truncation and we can just mul it normally
return Unsigned(a.rawValue.mul(b));
}
/**
* @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.
* @dev This will "floor" the quotient.
* @param a a FixedPoint numerator.
* @param b a FixedPoint denominator.
* @return the quotient of `a` divided by `b`.
*/
function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {
// There are two caveats with this computation:
// 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.
// 10^41 is stored internally as a uint256 10^59.
// 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which
// would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.
return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));
}
/**
* @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.
* @dev This will "floor" the quotient.
* @param a a FixedPoint numerator.
* @param b a uint256 denominator.
* @return the quotient of `a` divided by `b`.
*/
function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {
return Unsigned(a.rawValue.div(b));
}
/**
* @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.
* @dev This will "floor" the quotient.
* @param a a uint256 numerator.
* @param b a FixedPoint denominator.
* @return the quotient of `a` divided by `b`.
*/
function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {
return div(fromUnscaledUint(a), b);
}
/**
* @notice Divides one `Unsigned` by an `Unsigned` and "ceil's" the quotient, reverting on overflow or division by 0.
* @param a a FixedPoint numerator.
* @param b a FixedPoint denominator.
* @return the quotient of `a` divided by `b`.
*/
function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {
uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);
uint256 divFloor = aScaled.div(b.rawValue);
uint256 mod = aScaled.mod(b.rawValue);
if (mod != 0) {
return Unsigned(divFloor.add(1));
} else {
return Unsigned(divFloor);
}
}
/**
* @notice Divides one `Unsigned` by an unscaled uint256 and "ceil's" the quotient, reverting on overflow or division by 0.
* @param a a FixedPoint numerator.
* @param b a uint256 denominator.
* @return the quotient of `a` divided by `b`.
*/
function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {
// Because it is possible that a quotient gets truncated, we can't just call "Unsigned(a.rawValue.div(b))"
// similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.
// This creates the possibility of overflow if b is very large.
return divCeil(a, fromUnscaledUint(b));
}
/**
* @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.
* @dev This will "floor" the result.
* @param a a FixedPoint numerator.
* @param b a uint256 denominator.
* @return output is `a` to the power of `b`.
*/
function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {
output = fromUnscaledUint(1);
for (uint256 i = 0; i < b; i = i.add(1)) {
output = mul(output, a);
}
}
// ------------------------------------------------- SIGNED -------------------------------------------------------------
// Supports 18 decimals. E.g., 1e18 represents "1", 5e17 represents "0.5".
// For signed values:
// This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.
int256 private constant SFP_SCALING_FACTOR = 10**18;
struct Signed {
int256 rawValue;
}
function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {
require(a.rawValue >= 0, "Negative value provided");
return Unsigned(uint256(a.rawValue));
}
function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {
require(a.rawValue <= uint256(type(int256).max), "Unsigned too large");
return Signed(int256(a.rawValue));
}
/**
* @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.
* @param a int to convert into a FixedPoint.Signed.
* @return the converted FixedPoint.Signed.
*/
function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {
return Signed(a.mul(SFP_SCALING_FACTOR));
}
/**
* @notice Whether `a` is equal to `b`.
* @param a a FixedPoint.Signed.
* @param b a int256.
* @return True if equal, or False.
*/
function isEqual(Signed memory a, int256 b) internal pure returns (bool) {
return a.rawValue == fromUnscaledInt(b).rawValue;
}
/**
* @notice Whether `a` is equal to `b`.
* @param a a FixedPoint.Signed.
* @param b a FixedPoint.Signed.
* @return True if equal, or False.
*/
function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {
return a.rawValue == b.rawValue;
}
/**
* @notice Whether `a` is greater than `b`.
* @param a a FixedPoint.Signed.
* @param b a FixedPoint.Signed.
* @return True if `a > b`, or False.
*/
function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {
return a.rawValue > b.rawValue;
}
/**
* @notice Whether `a` is greater than `b`.
* @param a a FixedPoint.Signed.
* @param b an int256.
* @return True if `a > b`, or False.
*/
function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {
return a.rawValue > fromUnscaledInt(b).rawValue;
}
/**
* @notice Whether `a` is greater than `b`.
* @param a an int256.
* @param b a FixedPoint.Signed.
* @return True if `a > b`, or False.
*/
function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {
return fromUnscaledInt(a).rawValue > b.rawValue;
}
/**
* @notice Whether `a` is greater than or equal to `b`.
* @param a a FixedPoint.Signed.
* @param b a FixedPoint.Signed.
* @return True if `a >= b`, or False.
*/
function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {
return a.rawValue >= b.rawValue;
}
/**
* @notice Whether `a` is greater than or equal to `b`.
* @param a a FixedPoint.Signed.
* @param b an int256.
* @return True if `a >= b`, or False.
*/
function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {
return a.rawValue >= fromUnscaledInt(b).rawValue;
}
/**
* @notice Whether `a` is greater than or equal to `b`.
* @param a an int256.
* @param b a FixedPoint.Signed.
* @return True if `a >= b`, or False.
*/
function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {
return fromUnscaledInt(a).rawValue >= b.rawValue;
}
/**
* @notice Whether `a` is less than `b`.
* @param a a FixedPoint.Signed.
* @param b a FixedPoint.Signed.
* @return True if `a < b`, or False.
*/
function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {
return a.rawValue < b.rawValue;
}
/**
* @notice Whether `a` is less than `b`.
* @param a a FixedPoint.Signed.
* @param b an int256.
* @return True if `a < b`, or False.
*/
function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {
return a.rawValue < fromUnscaledInt(b).rawValue;
}
/**
* @notice Whether `a` is less than `b`.
* @param a an int256.
* @param b a FixedPoint.Signed.
* @return True if `a < b`, or False.
*/
function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {
return fromUnscaledInt(a).rawValue < b.rawValue;
}
/**
* @notice Whether `a` is less than or equal to `b`.
* @param a a FixedPoint.Signed.
* @param b a FixedPoint.Signed.
* @return True if `a <= b`, or False.
*/
function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {
return a.rawValue <= b.rawValue;
}
/**
* @notice Whether `a` is less than or equal to `b`.
* @param a a FixedPoint.Signed.
* @param b an int256.
* @return True if `a <= b`, or False.
*/
function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {
return a.rawValue <= fromUnscaledInt(b).rawValue;
}
/**
* @notice Whether `a` is less than or equal to `b`.
* @param a an int256.
* @param b a FixedPoint.Signed.
* @return True if `a <= b`, or False.
*/
function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {
return fromUnscaledInt(a).rawValue <= b.rawValue;
}
/**
* @notice The minimum of `a` and `b`.
* @param a a FixedPoint.Signed.
* @param b a FixedPoint.Signed.
* @return the minimum of `a` and `b`.
*/
function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {
return a.rawValue < b.rawValue ? a : b;
}
/**
* @notice The maximum of `a` and `b`.
* @param a a FixedPoint.Signed.
* @param b a FixedPoint.Signed.
* @return the maximum of `a` and `b`.
*/
function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {
return a.rawValue > b.rawValue ? a : b;
}
/**
* @notice Adds two `Signed`s, reverting on overflow.
* @param a a FixedPoint.Signed.
* @param b a FixedPoint.Signed.
* @return the sum of `a` and `b`.
*/
function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {
return Signed(a.rawValue.add(b.rawValue));
}
/**
* @notice Adds an `Signed` to an unscaled int, reverting on overflow.
* @param a a FixedPoint.Signed.
* @param b an int256.
* @return the sum of `a` and `b`.
*/
function add(Signed memory a, int256 b) internal pure returns (Signed memory) {
return add(a, fromUnscaledInt(b));
}
/**
* @notice Subtracts two `Signed`s, reverting on overflow.
* @param a a FixedPoint.Signed.
* @param b a FixedPoint.Signed.
* @return the difference of `a` and `b`.
*/
function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {
return Signed(a.rawValue.sub(b.rawValue));
}
/**
* @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.
* @param a a FixedPoint.Signed.
* @param b an int256.
* @return the difference of `a` and `b`.
*/
function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {
return sub(a, fromUnscaledInt(b));
}
/**
* @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.
* @param a an int256.
* @param b a FixedPoint.Signed.
* @return the difference of `a` and `b`.
*/
function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {
return sub(fromUnscaledInt(a), b);
}
/**
* @notice Multiplies two `Signed`s, reverting on overflow.
* @dev This will "floor" the product.
* @param a a FixedPoint.Signed.
* @param b a FixedPoint.Signed.
* @return the product of `a` and `b`.
*/
function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {
// There are two caveats with this computation:
// 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is
// stored internally as an int256 ~10^59.
// 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which
// would round to 3, but this computation produces the result 2.
// No need to use SafeMath because SFP_SCALING_FACTOR != 0.
return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);
}
/**
* @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.
* @dev This will "floor" the product.
* @param a a FixedPoint.Signed.
* @param b an int256.
* @return the product of `a` and `b`.
*/
function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {
return Signed(a.rawValue.mul(b));
}
/**
* @notice Multiplies two `Signed`s and "ceil's" the product, reverting on overflow.
* @param a a FixedPoint.Signed.
* @param b a FixedPoint.Signed.
* @return the product of `a` and `b`.
*/
function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {
int256 mulRaw = a.rawValue.mul(b.rawValue);
int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;
// Manual mod because SignedSafeMath doesn't support it.
int256 mod = mulRaw % SFP_SCALING_FACTOR;
if (mod != 0) {
bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);
int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);
return Signed(mulTowardsZero.add(valueToAdd));
} else {
return Signed(mulTowardsZero);
}
}
/**
* @notice Multiplies an `Signed` and an unscaled int256 and "ceil's" the product, reverting on overflow.
* @param a a FixedPoint.Signed.
* @param b a FixedPoint.Signed.
* @return the product of `a` and `b`.
*/
function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {
// Since b is an int, there is no risk of truncation and we can just mul it normally
return Signed(a.rawValue.mul(b));
}
/**
* @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.
* @dev This will "floor" the quotient.
* @param a a FixedPoint numerator.
* @param b a FixedPoint denominator.
* @return the quotient of `a` divided by `b`.
*/
function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {
// There are two caveats with this computation:
// 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.
// 10^41 is stored internally as an int256 10^59.
// 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which
// would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.
return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));
}
/**
* @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.
* @dev This will "floor" the quotient.
* @param a a FixedPoint numerator.
* @param b an int256 denominator.
* @return the quotient of `a` divided by `b`.
*/
function div(Signed memory a, int256 b) internal pure returns (Signed memory) {
return Signed(a.rawValue.div(b));
}
/**
* @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.
* @dev This will "floor" the quotient.
* @param a an int256 numerator.
* @param b a FixedPoint denominator.
* @return the quotient of `a` divided by `b`.
*/
function div(int256 a, Signed memory b) internal pure returns (Signed memory) {
return div(fromUnscaledInt(a), b);
}
/**
* @notice Divides one `Signed` by an `Signed` and "ceil's" the quotient, reverting on overflow or division by 0.
* @param a a FixedPoint numerator.
* @param b a FixedPoint denominator.
* @return the quotient of `a` divided by `b`.
*/
function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {
int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);
int256 divTowardsZero = aScaled.div(b.rawValue);
// Manual mod because SignedSafeMath doesn't support it.
int256 mod = aScaled % b.rawValue;
if (mod != 0) {
bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);
int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);
return Signed(divTowardsZero.add(valueToAdd));
} else {
return Signed(divTowardsZero);
}
}
/**
* @notice Divides one `Signed` by an unscaled int256 and "ceil's" the quotient, reverting on overflow or division by 0.
* @param a a FixedPoint numerator.
* @param b an int256 denominator.
* @return the quotient of `a` divided by `b`.
*/
function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {
// Because it is possible that a quotient gets truncated, we can't just call "Signed(a.rawValue.div(b))"
// similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.
// This creates the possibility of overflow if b is very large.
return divAwayFromZero(a, fromUnscaledInt(b));
}
/**
* @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.
* @dev This will "floor" the result.
* @param a a FixedPoint.Signed.
* @param b a uint256 (negative exponents are not allowed).
* @return output is `a` to the power of `b`.
*/
function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {
output = fromUnscaledInt(1);
for (uint256 i = 0; i < b; i = i.add(1)) {
output = mul(output, a);
}
}
}

AncillaryData.sol

// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.0;
/**
* @title Library for encoding and decoding ancillary data for DVM price requests.
* @notice We assume that on-chain ancillary data can be formatted directly from bytes to utf8 encoding via
* web3.utils.hexToUtf8, and that clients will parse the utf8-encoded ancillary data as a comma-delimitted key-value
* dictionary. Therefore, this library provides internal methods that aid appending to ancillary data from Solidity
* smart contracts. More details on UMA's ancillary data guidelines below:
* https://docs.google.com/document/d/1zhKKjgY1BupBGPPrY_WOJvui0B6DMcd-xDR8-9-SPDw/edit
*/
library AncillaryData {
// This converts the bottom half of a bytes32 input to hex in a highly gas-optimized way.
// Source: the brilliant implementation at https://gitter.im/ethereum/solidity?at=5840d23416207f7b0ed08c9b.
function toUtf8Bytes32Bottom(bytes32 bytesIn) private pure returns (bytes32) {
unchecked {
uint256 x = uint256(bytesIn);
// Nibble interleave
x = x & 0x00000000000000000000000000000000ffffffffffffffffffffffffffffffff;
x = (x | (x * 2**64)) & 0x0000000000000000ffffffffffffffff0000000000000000ffffffffffffffff;
x = (x | (x * 2**32)) & 0x00000000ffffffff00000000ffffffff00000000ffffffff00000000ffffffff;
x = (x | (x * 2**16)) & 0x0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff;
x = (x | (x * 2**8)) & 0x00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff;
x = (x | (x * 2**4)) & 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f;
// Hex encode
uint256 h = (x & 0x0808080808080808080808080808080808080808080808080808080808080808) / 8;
uint256 i = (x & 0x0404040404040404040404040404040404040404040404040404040404040404) / 4;
uint256 j = (x & 0x0202020202020202020202020202020202020202020202020202020202020202) / 2;
x = x + (h & (i | j)) * 0x27 + 0x3030303030303030303030303030303030303030303030303030303030303030;
// Return the result.
return bytes32(x);
}
}
/**
* @notice Returns utf8-encoded bytes32 string that can be read via web3.utils.hexToUtf8.
* @dev Will return bytes32 in all lower case hex characters and without the leading 0x.
* This has minor changes from the toUtf8BytesAddress to control for the size of the input.
* @param bytesIn bytes32 to encode.
* @return utf8 encoded bytes32.
*/
function toUtf8Bytes(bytes32 bytesIn) internal pure returns (bytes memory) {
return abi.encodePacked(toUtf8Bytes32Bottom(bytesIn >> 128), toUtf8Bytes32Bottom(bytesIn));
}
/**
* @notice Returns utf8-encoded address that can be read via web3.utils.hexToUtf8.
* Source: https://ethereum.stackexchange.com/questions/8346/convert-address-to-string/8447#8447
* @dev Will return address in all lower case characters and without the leading 0x.
* @param x address to encode.
* @return utf8 encoded address bytes.
*/
function toUtf8BytesAddress(address x) internal pure returns (bytes memory) {
return
abi.encodePacked(toUtf8Bytes32Bottom(bytes32(bytes20(x)) >> 128), bytes8(toUtf8Bytes32Bottom(bytes20(x))));
}
/**
* @notice Converts a uint into a base-10, UTF-8 representation stored in a `string` type.
* @dev This method is based off of this code: https://stackoverflow.com/a/65707309.
*/
function toUtf8BytesUint(uint256 x) internal pure returns (bytes memory) {
if (x == 0) {
return "0";
}
uint256 j = x;
uint256 len;
while (j != 0) {
len++;
j /= 10;
}
bytes memory bstr = new bytes(len);
uint256 k = len;
while (x != 0) {
k = k - 1;
uint8 temp = (48 + uint8(x - (x / 10) * 10));
bytes1 b1 = bytes1(temp);
bstr[k] = b1;
x /= 10;
}
return bstr;
}
function appendKeyValueBytes32(
bytes memory currentAncillaryData,
bytes memory key,
bytes32 value
) internal pure returns (bytes memory) {
bytes memory prefix = constructPrefix(currentAncillaryData, key);
return abi.encodePacked(currentAncillaryData, prefix, toUtf8Bytes(value));
}
/**
* @notice Adds "key:value" to `currentAncillaryData` where `value` is an address that first needs to be converted
* to utf8 bytes. For example, if `utf8(currentAncillaryData)="k1:v1"`, then this function will return
* `utf8(k1:v1,key:value)`, and if `currentAncillaryData` is blank, then this will return `utf8(key:value)`.
* @param currentAncillaryData This bytes data should ideally be able to be utf8-decoded, but its OK if not.
* @param key Again, this bytes data should ideally be able to be utf8-decoded, but its OK if not.
* @param value An address to set as the value in the key:value pair to append to `currentAncillaryData`.
* @return Newly appended ancillary data.
*/
function appendKeyValueAddress(
bytes memory currentAncillaryData,
bytes memory key,
address value
) internal pure returns (bytes memory) {
bytes memory prefix = constructPrefix(currentAncillaryData, key);
return abi.encodePacked(currentAncillaryData, prefix, toUtf8BytesAddress(value));
}
/**
* @notice Adds "key:value" to `currentAncillaryData` where `value` is a uint that first needs to be converted
* to utf8 bytes. For example, if `utf8(currentAncillaryData)="k1:v1"`, then this function will return
* `utf8(k1:v1,key:value)`, and if `currentAncillaryData` is blank, then this will return `utf8(key:value)`.
* @param currentAncillaryData This bytes data should ideally be able to be utf8-decoded, but its OK if not.
* @param key Again, this bytes data should ideally be able to be utf8-decoded, but its OK if not.
* @param value A uint to set as the value in the key:value pair to append to `currentAncillaryData`.
* @return Newly appended ancillary data.
*/
function appendKeyValueUint(
bytes memory currentAncillaryData,
bytes memory key,
uint256 value
) internal pure returns (bytes memory) {
bytes memory prefix = constructPrefix(currentAncillaryData, key);
return abi.encodePacked(currentAncillaryData, prefix, toUtf8BytesUint(value));
}
/**
* @notice Helper method that returns the left hand side of a "key:value" pair plus the colon ":" and a leading
* comma "," if the `currentAncillaryData` is not empty. The return value is intended to be prepended as a prefix to
* some utf8 value that is ultimately added to a comma-delimited, key-value dictionary.
*/
function constructPrefix(bytes memory currentAncillaryData, bytes memory key) internal pure returns (bytes memory) {
if (currentAncillaryData.length > 0) {
return abi.encodePacked(",", key, ":");
} else {
return abi.encodePacked(key, ":");
}
}
}

SignedSafeMath.sol

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @dev Wrappers over Solidity's arithmetic operations.
*
* NOTE: `SignedSafeMath` is no longer needed starting with Solidity 0.8. The compiler
* now has built in overflow checking.
*/
library SignedSafeMath {
/**
* @dev Returns the multiplication of two signed integers, reverting on
* overflow.
*
* Counterpart to Solidity's `*` operator.
*
* Requirements:
*
* - Multiplication cannot overflow.
*/
function mul(int256 a, int256 b) internal pure returns (int256) {
return a * b;
}
/**
* @dev Returns the integer division of two signed integers. Reverts on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator.
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function div(int256 a, int256 b) internal pure returns (int256) {
return a / b;
}
/**
* @dev Returns the subtraction of two signed integers, reverting on
* overflow.
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(int256 a, int256 b) internal pure returns (int256) {
return a - b;
}
/**
* @dev Returns the addition of two signed integers, reverting on
* overflow.
*
* Counterpart to Solidity's `+` operator.
*
* Requirements:
*
* - Addition cannot overflow.
*/
function add(int256 a, int256 b) internal pure returns (int256) {
return a + b;
}
}

SafeMath.sol

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
// CAUTION
// This version of SafeMath should only be used with Solidity 0.8 or later,
// because it relies on the compiler's built in overflow checks.
/**
* @dev Wrappers over Solidity's arithmetic operations.
*
* NOTE: `SafeMath` is no longer needed starting with Solidity 0.8. The compiler
* now has built in overflow checking.
*/
library SafeMath {
/**
* @dev Returns the addition of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the substraction of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b > a) return (false, 0);
return (true, a - b);
}
}
/**
* @dev Returns the multiplication of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the division of two unsigned integers, with a division by zero flag.
*
* _Available since v3.4._
*/
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a / b);
}
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
*
* _Available since v3.4._
*/
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a % b);
}
}
/**
* @dev Returns the addition of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `+` operator.
*
* Requirements:
*
* - Addition cannot overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
return a + b;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
return a - b;
}
/**
* @dev Returns the multiplication of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `*` operator.
*
* Requirements:
*
* - Multiplication cannot overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
return a * b;
}
/**
* @dev Returns the integer division of two unsigned integers, reverting on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator.
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
return a / b;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* reverting when dividing by zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
return a % b;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting with custom message on
* overflow (when the result is negative).
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {trySub}.
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(
uint256 a,
uint256 b,
string memory errorMessage
) internal pure returns (uint256) {
unchecked {
require(b <= a, errorMessage);
return a - b;
}
}
/**
* @dev Returns the integer division of two unsigned integers, reverting with custom message on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function div(
uint256 a,
uint256 b,
string memory errorMessage
) internal pure returns (uint256) {
unchecked {
require(b > 0, errorMessage);
return a / b;
}
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* reverting with custom message when dividing by zero.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryMod}.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function mod(
uint256 a,
uint256 b,
string memory errorMessage
) internal pure returns (uint256) {
unchecked {
require(b > 0, errorMessage);
return a % b;
}
}
}

Math.sol

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a >= b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow, so we distribute.
return (a / 2) + (b / 2) + (((a % 2) + (b % 2)) / 2);
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds up instead
* of rounding down.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b - 1) / b can overflow on addition, so we distribute.
return a / b + (a % b == 0 ? 0 : 1);
}
}

Address.sol

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize, which returns 0 for contracts in
// construction, since the code is only stored at the end of the
// constructor execution.
uint256 size;
assembly {
size := extcodesize(account)
}
return size > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return _verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return _verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
require(isContract(target), "Address: delegate call to non-contract");
(bool success, bytes memory returndata) = target.delegatecall(data);
return _verifyCallResult(success, returndata, errorMessage);
}
function _verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) private pure returns (bytes memory) {
if (success) {
return returndata;
} else {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}

SafeERC20.sol

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../../../utils/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using Address for address;
function safeTransfer(
IERC20 token,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(
IERC20 token,
address from,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
/**
* @dev Deprecated. This function has issues similar to the ones found in
* {IERC20-approve}, and its usage is discouraged.
*
* Whenever possible, use {safeIncreaseAllowance} and
* {safeDecreaseAllowance} instead.
*/
function safeApprove(
IERC20 token,
address spender,
uint256 value
) internal {
// safeApprove should only be called when setting an initial allowance,
// or when resetting it to zero. To increase and decrease it, use
// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function safeIncreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
uint256 newAllowance = token.allowance(address(this), spender) + value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function safeDecreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
uint256 newAllowance = oldAllowance - value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
if (returndata.length > 0) {
// Return data is optional
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}

IERC20.sol

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `recipient`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address recipient, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `sender` to `recipient` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(
address sender,
address recipient,
uint256 amount
) external returns (bool);
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
}

Contract ABI

[{"type":"event","name":"VaultDeposited","inputs":[{"type":"address","name":"user","internalType":"address","indexed":false},{"type":"address","name":"lsp","internalType":"address","indexed":false},{"type":"uint256","name":"amountUSDC","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"arbitrage","inputs":[{"type":"uint256","name":"amount","internalType":"uint256"},{"type":"uint256","name":"tokensToBuy","internalType":"uint256"},{"type":"address","name":"lsp","internalType":"contract LongShortPair"},{"type":"address","name":"router","internalType":"contract IUniswapV2Router02"},{"type":"uint256","name":"deadline","internalType":"uint256"},{"type":"tuple","name":"usdcSignature","internalType":"struct Vault.Signature","components":[{"type":"uint8","name":"v","internalType":"uint8"},{"type":"bytes32","name":"r","internalType":"bytes32"},{"type":"bytes32","name":"s","internalType":"bytes32"}]}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"deposit","inputs":[{"type":"uint256","name":"usdcForArb","internalType":"uint256"},{"type":"uint256","name":"tokensToBuyForArb","internalType":"uint256"},{"type":"address","name":"router","internalType":"contract IUniswapV2Router02"},{"type":"tuple","name":"priceDeviation_","internalType":"struct FixedPoint.Unsigned","components":[{"type":"uint256","name":"rawValue","internalType":"uint256"}]},{"type":"address","name":"lsp","internalType":"contract LongShortPair"},{"type":"tuple","name":"usdcSignature","internalType":"struct Vault.Signature","components":[{"type":"uint8","name":"v","internalType":"uint8"},{"type":"bytes32","name":"r","internalType":"bytes32"},{"type":"bytes32","name":"s","internalType":"bytes32"}]},{"type":"uint256","name":"amount","internalType":"uint256"},{"type":"address","name":"longStaking","internalType":"contract IERC900"},{"type":"address","name":"shortStaking","internalType":"contract IERC900"},{"type":"uint256","name":"deadline","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"depositedFor","inputs":[{"type":"address","name":"factory","internalType":"contract IUniswapV2Factory"},{"type":"address","name":"lsp","internalType":"contract LongShortPair"},{"type":"address","name":"longStaking","internalType":"contract IERC900"},{"type":"address","name":"shortStaking","internalType":"contract IERC900"},{"type":"address","name":"user","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"rescue","inputs":[{"type":"address","name":"token","internalType":"contract IERC20"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"withdraw","inputs":[{"type":"tuple","name":"priceDeviation_","internalType":"struct FixedPoint.Unsigned","components":[{"type":"uint256","name":"rawValue","internalType":"uint256"}]},{"type":"address","name":"lsp","internalType":"contract LongShortPair"},{"type":"uint256","name":"longLPAmount","internalType":"uint256"},{"type":"uint256","name":"shortLPAmount","internalType":"uint256"},{"type":"address","name":"router","internalType":"contract IUniswapV2Router02"},{"type":"uint256","name":"deadline","internalType":"uint256"},{"type":"tuple","name":"longSignature","internalType":"struct Vault.Signature","components":[{"type":"uint8","name":"v","internalType":"uint8"},{"type":"bytes32","name":"r","internalType":"bytes32"},{"type":"bytes32","name":"s","internalType":"bytes32"}]},{"type":"tuple","name":"shortSignature","internalType":"struct Vault.Signature","components":[{"type":"uint8","name":"v","internalType":"uint8"},{"type":"bytes32","name":"r","internalType":"bytes32"},{"type":"bytes32","name":"s","internalType":"bytes32"}]},{"type":"uint8","name":"withdrawMode","internalType":"enum Vault.WithdrawMode"}]}]
            

Deployed ByteCode

0x608060405234801561001057600080fd5b50600436106100575760003560e01c80635d2ac0c01461005c578063725049271461008c578063839006f2146100a85780638cd4fd3a146100c4578063e9c60fb2146100e0575b600080fd5b61007660048036038101906100719190614a29565b6100fc565b604051610083919061544c565b60405180910390f35b6100a660048036038101906100a19190614cea565b610923565b005b6100c260048036038101906100bd91906149cf565b610b3b565b005b6100de60048036038101906100d99190614aa4565b610c54565b005b6100fa60048036038101906100f59190614c09565b611c4a565b005b6000808573ffffffffffffffffffffffffffffffffffffffff1663b2016bd46040518163ffffffff1660e01b815260040160206040518083038186803b15801561014557600080fd5b505afa158015610159573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061017d91906149fc565b905060008773ffffffffffffffffffffffffffffffffffffffff1663e6a439058873ffffffffffffffffffffffffffffffffffffffff1663b66333cd6040518163ffffffff1660e01b815260040160206040518083038186803b1580156101e357600080fd5b505afa1580156101f7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061021b91906149a2565b846040518363ffffffff1660e01b81526004016102399291906150e5565b60206040518083038186803b15801561025157600080fd5b505afa158015610265573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061028991906148ff565b905060008873ffffffffffffffffffffffffffffffffffffffff1663e6a439058973ffffffffffffffffffffffffffffffffffffffff1663e3065da76040518163ffffffff1660e01b815260040160206040518083038186803b1580156102ef57600080fd5b505afa158015610303573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061032791906149a2565b856040518363ffffffff1660e01b81526004016103459291906150e5565b60206040518083038186803b15801561035d57600080fd5b505afa158015610371573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061039591906148ff565b905060008373ffffffffffffffffffffffffffffffffffffffff166370a08231846040518263ffffffff1660e01b81526004016103d291906150ca565b60206040518083038186803b1580156103ea57600080fd5b505afa1580156103fe573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104229190614b9c565b905060008473ffffffffffffffffffffffffffffffffffffffff166370a08231846040518263ffffffff1660e01b815260040161045f91906150ca565b60206040518083038186803b15801561047757600080fd5b505afa15801561048b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104af9190614b9c565b905060006106aa8573ffffffffffffffffffffffffffffffffffffffff166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b1580156104fc57600080fd5b505afa158015610510573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105349190614b9c565b61069c600073ffffffffffffffffffffffffffffffffffffffff168d73ffffffffffffffffffffffffffffffffffffffff1614156105735760006105fd565b8c73ffffffffffffffffffffffffffffffffffffffff16634b341aed8c6040518263ffffffff1660e01b81526004016105ac91906150ca565b60206040518083038186803b1580156105c457600080fd5b505afa1580156105d8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105fc9190614b9c565b5b61068e8973ffffffffffffffffffffffffffffffffffffffff166370a082318e6040518263ffffffff1660e01b815260040161063991906150ca565b60206040518083038186803b15801561065157600080fd5b505afa158015610665573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106899190614b9c565b612a84565b612abc90919063ffffffff16565b612ade90919063ffffffff16565b905060006108a58573ffffffffffffffffffffffffffffffffffffffff166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b1580156106f757600080fd5b505afa15801561070b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061072f9190614b9c565b610897600073ffffffffffffffffffffffffffffffffffffffff168d73ffffffffffffffffffffffffffffffffffffffff16141561076e5760006107f8565b8c73ffffffffffffffffffffffffffffffffffffffff16634b341aed8d6040518263ffffffff1660e01b81526004016107a791906150ca565b60206040518083038186803b1580156107bf57600080fd5b505afa1580156107d3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107f79190614b9c565b5b6108898973ffffffffffffffffffffffffffffffffffffffff166370a082318f6040518263ffffffff1660e01b815260040161083491906150ca565b60206040518083038186803b15801561084c57600080fd5b505afa158015610860573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108849190614b9c565b612a84565b612abc90919063ffffffff16565b612ade90919063ffffffff16565b905061090d60026108ff6108d060405180602001604052808881525085612b1390919063ffffffff16565b6108f160405180602001604052808a81525087612b1390919063ffffffff16565b612b5f90919063ffffffff16565b612b9890919063ffffffff16565b6000015197505050505050505095945050505050565b60008473ffffffffffffffffffffffffffffffffffffffff1663b2016bd46040518163ffffffff1660e01b815260040160206040518083038186803b15801561096b57600080fd5b505afa15801561097f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109a391906149fc565b90506109ae82612bcd565b15610a45578073ffffffffffffffffffffffffffffffffffffffff1663d505accf33308a878760000160208101906109e69190614dcb565b886020013589604001356040518863ffffffff1660e01b8152600401610a129796959493929190615232565b600060405180830381600087803b158015610a2c57600080fd5b505af1158015610a40573d6000803e3d6000fd5b505050505b610a723330898473ffffffffffffffffffffffffffffffffffffffff16612c15909392919063ffffffff16565b610a7f8787878787612c9e565b610b32338273ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401610abc91906150ca565b60206040518083038186803b158015610ad457600080fd5b505afa158015610ae8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b0c9190614b9c565b8373ffffffffffffffffffffffffffffffffffffffff166139ce9092919063ffffffff16565b50505050505050565b8073ffffffffffffffffffffffffffffffffffffffff1663a9059cbb338373ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401610b9191906150ca565b60206040518083038186803b158015610ba957600080fd5b505afa158015610bbd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610be19190614b9c565b6040518363ffffffff1660e01b8152600401610bfe9291906152a1565b602060405180830381600087803b158015610c1857600080fd5b505af1158015610c2c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c509190614975565b5050565b60008873ffffffffffffffffffffffffffffffffffffffff1663b66333cd6040518163ffffffff1660e01b815260040160206040518083038186803b158015610c9c57600080fd5b505afa158015610cb0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cd491906149a2565b905060008973ffffffffffffffffffffffffffffffffffffffff1663e3065da76040518163ffffffff1660e01b815260040160206040518083038186803b158015610d1e57600080fd5b505afa158015610d32573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d5691906149a2565b905060008773ffffffffffffffffffffffffffffffffffffffff1663c45a01556040518163ffffffff1660e01b815260040160206040518083038186803b158015610da057600080fd5b505afa158015610db4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dd891906148ff565b9050610de783838e8e85613a54565b5050505060008060008973ffffffffffffffffffffffffffffffffffffffff1663c45a01556040518163ffffffff1660e01b815260040160206040518083038186803b158015610e3657600080fd5b505afa158015610e4a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e6e91906148ff565b905060008d73ffffffffffffffffffffffffffffffffffffffff1663b2016bd46040518163ffffffff1660e01b815260040160206040518083038186803b158015610eb857600080fd5b505afa158015610ecc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ef091906149fc565b90508173ffffffffffffffffffffffffffffffffffffffff1663e6a4390587836040518363ffffffff1660e01b8152600401610f2d9291906150e5565b60206040518083038186803b158015610f4557600080fd5b505afa158015610f59573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f7d91906148ff565b93508173ffffffffffffffffffffffffffffffffffffffff1663e6a4390586836040518363ffffffff1660e01b8152600401610fba9291906150e5565b60206040518083038186803b158015610fd257600080fd5b505afa158015610fe6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061100a91906148ff565b9250505061101787612bcd565b156110ae578173ffffffffffffffffffffffffffffffffffffffff1663d505accf33308e8c8c600001602081019061104f9190614dcb565b8d602001358e604001356040518863ffffffff1660e01b815260040161107b9796959493929190615232565b600060405180830381600087803b15801561109557600080fd5b505af11580156110a9573d6000803e3d6000fd5b505050505b6110b786612bcd565b1561114e578073ffffffffffffffffffffffffffffffffffffffff1663d505accf33308d8c8b60000160208101906110ef9190614dcb565b8c602001358d604001356040518863ffffffff1660e01b815260040161111b9796959493929190615232565b600060405180830381600087803b15801561113557600080fd5b505af1158015611149573d6000803e3d6000fd5b505050505b8073ffffffffffffffffffffffffffffffffffffffff1663095ea7b38a8c6040518363ffffffff1660e01b81526004016111899291906152a1565b602060405180830381600087803b1580156111a357600080fd5b505af11580156111b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111db9190614975565b508173ffffffffffffffffffffffffffffffffffffffff1663095ea7b38a8d6040518363ffffffff1660e01b81526004016112179291906152a1565b602060405180830381600087803b15801561123157600080fd5b505af1158015611245573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112699190614975565b5061129733308d8573ffffffffffffffffffffffffffffffffffffffff16612c15909392919063ffffffff16565b6112c433308c8473ffffffffffffffffffffffffffffffffffffffff16612c15909392919063ffffffff16565b505060008a73ffffffffffffffffffffffffffffffffffffffff1663b2016bd46040518163ffffffff1660e01b815260040160206040518083038186803b15801561130e57600080fd5b505afa158015611322573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061134691906149fc565b9050600080600281111561135d5761135c615a9f565b5b8560028111156113705761136f615a9f565b5b1461137b573061137d565b335b90508873ffffffffffffffffffffffffffffffffffffffff1663baa2abde85848e600080878f6040518863ffffffff1660e01b81526004016113c59796959493929190615145565b6040805180830381600087803b1580156113de57600080fd5b505af11580156113f2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114169190614bc9565b50508873ffffffffffffffffffffffffffffffffffffffff1663baa2abde84848d600080878f6040518863ffffffff1660e01b815260040161145e9796959493929190615145565b6040805180830381600087803b15801561147757600080fd5b505af115801561148b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114af9190614bc9565b5050600160028111156114c5576114c4615a9f565b5b8560028111156114d8576114d7615a9f565b5b14156119bc5760008373ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b815260040161151991906150ca565b60206040518083038186803b15801561153157600080fd5b505afa158015611545573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115699190614b9c565b8573ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b81526004016115a291906150ca565b60206040518083038186803b1580156115ba57600080fd5b505afa1580156115ce573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115f29190614b9c565b11611685578473ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b815260040161163091906150ca565b60206040518083038186803b15801561164857600080fd5b505afa15801561165c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116809190614b9c565b61170f565b8373ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b81526004016116be91906150ca565b60206040518083038186803b1580156116d657600080fd5b505afa1580156116ea573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061170e9190614b9c565b5b90508c73ffffffffffffffffffffffffffffffffffffffff1663db006a75826040518263ffffffff1660e01b815260040161174a919061544c565b602060405180830381600087803b15801561176457600080fd5b505af1158015611778573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061179c9190614b9c565b50611850338473ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b81526004016117da91906150ca565b60206040518083038186803b1580156117f257600080fd5b505afa158015611806573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061182a9190614b9c565b8573ffffffffffffffffffffffffffffffffffffffff166139ce9092919063ffffffff16565b611903338673ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b815260040161188d91906150ca565b60206040518083038186803b1580156118a557600080fd5b505afa1580156118b9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118dd9190614b9c565b8773ffffffffffffffffffffffffffffffffffffffff166139ce9092919063ffffffff16565b6119b6338573ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b815260040161194091906150ca565b60206040518083038186803b15801561195857600080fd5b505afa15801561196c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119909190614b9c565b8673ffffffffffffffffffffffffffffffffffffffff166139ce9092919063ffffffff16565b50611c3b565b6002808111156119cf576119ce615a9f565b5b8560028111156119e2576119e1615a9f565b5b1415611c3a578b73ffffffffffffffffffffffffffffffffffffffff16639a9c29f68573ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401611a3d91906150ca565b60206040518083038186803b158015611a5557600080fd5b505afa158015611a69573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a8d9190614b9c565b8573ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401611ac691906150ca565b60206040518083038186803b158015611ade57600080fd5b505afa158015611af2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b169190614b9c565b6040518363ffffffff1660e01b8152600401611b339291906154c1565b602060405180830381600087803b158015611b4d57600080fd5b505af1158015611b61573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b859190614b9c565b50611c39338373ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401611bc391906150ca565b60206040518083038186803b158015611bdb57600080fd5b505afa158015611bef573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c139190614b9c565b8473ffffffffffffffffffffffffffffffffffffffff166139ce9092919063ffffffff16565b5b5b50505050505050505050505050565b42811015611c8d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611c849061538c565b60405180910390fd5b60008673ffffffffffffffffffffffffffffffffffffffff1663b2016bd46040518163ffffffff1660e01b815260040160206040518083038186803b158015611cd557600080fd5b505afa158015611ce9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d0d91906149fc565b9050611d1886612bcd565b15611daf578073ffffffffffffffffffffffffffffffffffffffff1663d505accf333088868b6000016020810190611d509190614dcb565b8c602001358d604001356040518863ffffffff1660e01b8152600401611d7c9796959493929190615232565b600060405180830381600087803b158015611d9657600080fd5b505af1158015611daa573d6000803e3d6000fd5b505050505b611ddc3330878473ffffffffffffffffffffffffffffffffffffffff16612c15909392919063ffffffff16565b60008b1115611e7e57611df28b8b898c86612c9e565b8073ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401611e2b91906150ca565b60206040518083038186803b158015611e4357600080fd5b505afa158015611e57573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e7b9190614b9c565b94505b600080600080611e908d8d8d8c613c0e565b935093509350935088838284611ea69190615600565b611eb09190615600565b1115611ef1576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611ee8906153cc565b60405180910390fd5b8473ffffffffffffffffffffffffffffffffffffffff1663095ea7b38c856040518363ffffffff1660e01b8152600401611f2c9291906152a1565b602060405180830381600087803b158015611f4657600080fd5b505af1158015611f5a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f7e9190614975565b508a73ffffffffffffffffffffffffffffffffffffffff1663780900dc856040518263ffffffff1660e01b8152600401611fb8919061544c565b602060405180830381600087803b158015611fd257600080fd5b505af1158015611fe6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061200a9190614b9c565b508473ffffffffffffffffffffffffffffffffffffffff1663095ea7b38e84846120349190615600565b6040518363ffffffff1660e01b81526004016120519291906152a1565b602060405180830381600087803b15801561206b57600080fd5b505af115801561207f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120a39190614975565b5060008d905060008c73ffffffffffffffffffffffffffffffffffffffff1663b66333cd6040518163ffffffff1660e01b815260040160206040518083038186803b1580156120f157600080fd5b505afa158015612105573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061212991906149a2565b90508073ffffffffffffffffffffffffffffffffffffffff1663095ea7b383886040518363ffffffff1660e01b81526004016121669291906152a1565b602060405180830381600087803b15801561218057600080fd5b505af1158015612194573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121b89190614975565b50600088905060008073ffffffffffffffffffffffffffffffffffffffff168c73ffffffffffffffffffffffffffffffffffffffff16146121f957306121fb565b335b90508373ffffffffffffffffffffffffffffffffffffffff1663e8e33700848b8b8a8d8c888a6040518963ffffffff1660e01b81526004016122449897969594939291906151b4565b606060405180830381600087803b15801561225e57600080fd5b505af1158015612272573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122969190614d78565b5050505050600073ffffffffffffffffffffffffffffffffffffffff168a73ffffffffffffffffffffffffffffffffffffffff161461256c5760008f73ffffffffffffffffffffffffffffffffffffffff1663c45a01556040518163ffffffff1660e01b815260040160206040518083038186803b15801561231757600080fd5b505afa15801561232b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061234f91906148ff565b905060008173ffffffffffffffffffffffffffffffffffffffff1663e6a43905848b6040518363ffffffff1660e01b815260040161238e9291906150e5565b60206040518083038186803b1580156123a657600080fd5b505afa1580156123ba573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123de91906148ff565b905060008173ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b815260040161241b91906150ca565b60206040518083038186803b15801561243357600080fd5b505afa158015612447573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061246b9190614b9c565b90508173ffffffffffffffffffffffffffffffffffffffff1663095ea7b38e836040518363ffffffff1660e01b81526004016124a89291906152a1565b602060405180830381600087803b1580156124c257600080fd5b505af11580156124d6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124fa9190614975565b508c73ffffffffffffffffffffffffffffffffffffffff16632ee4090833836040518363ffffffff1660e01b81526004016125369291906152a1565b600060405180830381600087803b15801561255057600080fd5b505af1158015612564573d6000803e3d6000fd5b505050505050505b505060008d905060008c73ffffffffffffffffffffffffffffffffffffffff1663e3065da76040518163ffffffff1660e01b815260040160206040518083038186803b1580156125bb57600080fd5b505afa1580156125cf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125f391906149a2565b90508073ffffffffffffffffffffffffffffffffffffffff1663095ea7b383886040518363ffffffff1660e01b81526004016126309291906152a1565b602060405180830381600087803b15801561264a57600080fd5b505af115801561265e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126829190614975565b50600088905060008073ffffffffffffffffffffffffffffffffffffffff168b73ffffffffffffffffffffffffffffffffffffffff16146126c357306126c5565b335b90508373ffffffffffffffffffffffffffffffffffffffff1663e8e33700848b8b898d8b888a6040518963ffffffff1660e01b815260040161270e9897969594939291906151b4565b606060405180830381600087803b15801561272857600080fd5b505af115801561273c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127609190614d78565b5050505050600073ffffffffffffffffffffffffffffffffffffffff168973ffffffffffffffffffffffffffffffffffffffff1614612a365760008f73ffffffffffffffffffffffffffffffffffffffff1663c45a01556040518163ffffffff1660e01b815260040160206040518083038186803b1580156127e157600080fd5b505afa1580156127f5573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061281991906148ff565b905060008173ffffffffffffffffffffffffffffffffffffffff1663e6a43905848b6040518363ffffffff1660e01b81526004016128589291906150e5565b60206040518083038186803b15801561287057600080fd5b505afa158015612884573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128a891906148ff565b905060008173ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b81526004016128e591906150ca565b60206040518083038186803b1580156128fd57600080fd5b505afa158015612911573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129359190614b9c565b90508173ffffffffffffffffffffffffffffffffffffffff1663095ea7b38d836040518363ffffffff1660e01b81526004016129729291906152a1565b602060405180830381600087803b15801561298c57600080fd5b505af11580156129a0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129c49190614975565b508b73ffffffffffffffffffffffffffffffffffffffff16632ee4090833836040518363ffffffff1660e01b8152600401612a009291906152a1565b600060405180830381600087803b158015612a1a57600080fd5b505af1158015612a2e573d6000803e3d6000fd5b505050505050505b50507f2df8a6513637b00c16fac19a51061303422765fbadb402cc90d7b42acee9cf7d338c8b604051612a6b9392919061510e565b60405180910390a1505050505050505050505050505050565b612a8c61469b565b6040518060200160405280612ab2670de0b6b3a764000085613e8390919063ffffffff16565b8152509050919050565b612ac461469b565b612ad683612ad184612a84565b612b5f565b905092915050565b612ae661469b565b6040518060200160405280612b08848660000151613e9990919063ffffffff16565b815250905092915050565b612b1b61469b565b6040518060200160405280670de0b6b3a7640000612b4a85600001518760000151613e8390919063ffffffff16565b612b5491906156c0565b815250905092915050565b612b6761469b565b6040518060200160405280612b8d84600001518660000151613eaf90919063ffffffff16565b815250905092915050565b612ba061469b565b6040518060200160405280612bc2848660000151613e8390919063ffffffff16565b815250905092915050565b600080826000016020810190612be39190614dcb565b60ff1614158015612bfb57506000801b826020013514155b8015612c0e57506000801b826040013514155b9050919050565b612c98846323b872dd60e01b858585604051602401612c369392919061510e565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050613ec5565b50505050565b60008511612ce1576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612cd89061540c565b60405180910390fd5b60008373ffffffffffffffffffffffffffffffffffffffff1663b2016bd46040518163ffffffff1660e01b815260040160206040518083038186803b158015612d2957600080fd5b505afa158015612d3d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d6191906149fc565b905060008473ffffffffffffffffffffffffffffffffffffffff1663b66333cd6040518163ffffffff1660e01b815260040160206040518083038186803b158015612dab57600080fd5b505afa158015612dbf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612de391906149a2565b905060008573ffffffffffffffffffffffffffffffffffffffff1663e3065da76040518163ffffffff1660e01b815260040160206040518083038186803b158015612e2d57600080fd5b505afa158015612e41573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e6591906149a2565b905060008373ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401612ea291906150ca565b60206040518083038186803b158015612eba57600080fd5b505afa158015612ece573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ef29190614b9c565b905060008811156133a6578373ffffffffffffffffffffffffffffffffffffffff1663095ea7b3878b6040518363ffffffff1660e01b8152600401612f389291906152a1565b602060405180830381600087803b158015612f5257600080fd5b505af1158015612f66573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f8a9190614975565b506000600267ffffffffffffffff811115612fa857612fa7615afd565b5b604051908082528060200260200182016040528015612fd65781602001602082028036833780820191505090505b5090508481600081518110612fee57612fed615ace565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050838160018151811061303d5761303c615ace565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508673ffffffffffffffffffffffffffffffffffffffff16638803dbee8a8c84308b6040518663ffffffff1660e01b81526004016130b89594939291906154ea565b600060405180830381600087803b1580156130d257600080fd5b505af11580156130e6573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f8201168201806040525081019061310f919061492c565b50828160018151811061312557613124615ace565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508673ffffffffffffffffffffffffffffffffffffffff16638803dbee8a8c84308b6040518663ffffffff1660e01b81526004016131a09594939291906154ea565b600060405180830381600087803b1580156131ba57600080fd5b505af11580156131ce573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f820116820180604052508101906131f7919061492c565b508373ffffffffffffffffffffffffffffffffffffffff1663095ea7b3898b6040518363ffffffff1660e01b81526004016132339291906152a1565b602060405180830381600087803b15801561324d57600080fd5b505af1158015613261573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132859190614975565b508273ffffffffffffffffffffffffffffffffffffffff1663095ea7b3898b6040518363ffffffff1660e01b81526004016132c19291906152a1565b602060405180830381600087803b1580156132db57600080fd5b505af11580156132ef573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133139190614975565b508773ffffffffffffffffffffffffffffffffffffffff1663db006a758a6040518263ffffffff1660e01b815260040161334d919061544c565b602060405180830381600087803b15801561336757600080fd5b505af115801561337b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061339f9190614b9c565b50506138f3565b8373ffffffffffffffffffffffffffffffffffffffff1663095ea7b3888b6040518363ffffffff1660e01b81526004016133e19291906152a1565b602060405180830381600087803b1580156133fb57600080fd5b505af115801561340f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134339190614975565b5060006134406001612a84565b600001518873ffffffffffffffffffffffffffffffffffffffff1663e964ae026040518163ffffffff1660e01b815260040160206040518083038186803b15801561348a57600080fd5b505afa15801561349e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134c29190614b9c565b6134cc91906156c0565b8a6134d791906156c0565b90508773ffffffffffffffffffffffffffffffffffffffff1663780900dc826040518263ffffffff1660e01b8152600401613512919061544c565b602060405180830381600087803b15801561352c57600080fd5b505af1158015613540573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135649190614b9c565b508373ffffffffffffffffffffffffffffffffffffffff1663095ea7b388836040518363ffffffff1660e01b81526004016135a09291906152a1565b602060405180830381600087803b1580156135ba57600080fd5b505af11580156135ce573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135f29190614975565b508273ffffffffffffffffffffffffffffffffffffffff1663095ea7b388836040518363ffffffff1660e01b815260040161362e9291906152a1565b602060405180830381600087803b15801561364857600080fd5b505af115801561365c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136809190614975565b506000600267ffffffffffffffff81111561369e5761369d615afd565b5b6040519080825280602002602001820160405280156136cc5781602001602082028036833780820191505090505b50905085816001815181106136e4576136e3615ace565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050848160008151811061373357613732615ace565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508773ffffffffffffffffffffffffffffffffffffffff166338ed173983600084308c6040518663ffffffff1660e01b81526004016137af959493929190615467565b600060405180830381600087803b1580156137c957600080fd5b505af11580156137dd573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250810190613806919061492c565b50838160008151811061381c5761381b615ace565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508773ffffffffffffffffffffffffffffffffffffffff166338ed173983600084308c6040518663ffffffff1660e01b8152600401613898959493929190615467565b600060405180830381600087803b1580156138b257600080fd5b505af11580156138c6573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f820116820180604052508101906138ef919061492c565b5050505b60008473ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b815260040161392e91906150ca565b60206040518083038186803b15801561394657600080fd5b505afa15801561395a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061397e9190614b9c565b90508181116139c2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016139b99061542c565b60405180910390fd5b50505050505050505050565b613a4f8363a9059cbb60e01b84846040516024016139ed9291906152a1565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050613ec5565b505050565b613a5c61469b565b613a6461469b565b613a6c61469b565b60008573ffffffffffffffffffffffffffffffffffffffff1663b2016bd46040518163ffffffff1660e01b815260040160206040518083038186803b158015613ab457600080fd5b505afa158015613ac8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613aec91906149fc565b9050613af9898287613f8c565b9350613b06888287613f8c565b925060405180602001604052808773ffffffffffffffffffffffffffffffffffffffff1663e964ae026040518163ffffffff1660e01b815260040160206040518083038186803b158015613b5957600080fd5b505afa158015613b6d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b919190614b9c565b8152509150613bc387803603810190613baa9190614b6f565b613bb58686866141a7565b61421390919063ffffffff16565b613c02576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401613bf9906152ec565b60405180910390fd5b50955095509592505050565b60008060008060008673ffffffffffffffffffffffffffffffffffffffff1663b66333cd6040518163ffffffff1660e01b815260040160206040518083038186803b158015613c5c57600080fd5b505afa158015613c70573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c9491906149a2565b905060008773ffffffffffffffffffffffffffffffffffffffff1663e3065da76040518163ffffffff1660e01b815260040160206040518083038186803b158015613cde57600080fd5b505afa158015613cf2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d1691906149a2565b905060008a73ffffffffffffffffffffffffffffffffffffffff1663c45a01556040518163ffffffff1660e01b815260040160206040518083038186803b158015613d6057600080fd5b505afa158015613d74573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d9891906148ff565b90506000806000613dac86868f8f88613a54565b925092509250613df7613dda83613dcc8685612b5f90919063ffffffff16565b612b5f90919063ffffffff16565b60405180602001604052808e81525061422990919063ffffffff16565b600001519950613e1e60405180602001604052808c81525082612b1390919063ffffffff16565b600001519850613e4560405180602001604052808c81525084612b1390919063ffffffff16565b600001519750613e6c60405180602001604052808c81525083612b1390919063ffffffff16565b600001519650505050505050945094509450949050565b60008183613e919190615808565b905092915050565b60008183613ea791906156c0565b905092915050565b60008183613ebd9190615600565b905092915050565b6000613f27826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff1661427c9092919063ffffffff16565b9050600081511115613f875780806020019051810190613f479190614975565b613f86576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401613f7d906153ec565b60405180910390fd5b5b505050565b613f9461469b565b60008273ffffffffffffffffffffffffffffffffffffffff1663e6a4390586866040518363ffffffff1660e01b8152600401613fd19291906150e5565b60206040518083038186803b158015613fe957600080fd5b505afa158015613ffd573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061402191906148ff565b905060006140b68573ffffffffffffffffffffffffffffffffffffffff166370a08231846040518263ffffffff1660e01b815260040161406191906150ca565b60206040518083038186803b15801561407957600080fd5b505afa15801561408d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140b19190614b9c565b612a84565b905060008673ffffffffffffffffffffffffffffffffffffffff166370a08231846040518263ffffffff1660e01b81526004016140f391906150ca565b60206040518083038186803b15801561410b57600080fd5b505afa15801561411f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141439190614b9c565b905060008111614188576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161417f9061536c565b60405180910390fd5b61419b8183612ade90919063ffffffff16565b93505050509392505050565b6141af61469b565b60006141ba83614294565b905060006141eb826141dd6141d8888a612b5f90919063ffffffff16565b614294565b61431d90919063ffffffff16565b9050614208614203838361435690919063ffffffff16565b6143a9565b925050509392505050565b6000816000015183600001511115905092915050565b61423161469b565b60405180602001604052806142718460000151614263670de0b6b3a76400008860000151613e8390919063ffffffff16565b613e9990919063ffffffff16565b815250905092915050565b606061428b848460008561440c565b90509392505050565b61429c6146ae565b7f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82600001511115614303576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016142fa9061534c565b60405180910390fd5b604051806020016040528083600001518152509050919050565b6143256146ae565b604051806020016040528061434b8460000151866000015161452090919063ffffffff16565b815250905092915050565b61435e6146ae565b604051806020016040528061439e8460000151614390670de0b6b3a7640000886000015161453690919063ffffffff16565b61454c90919063ffffffff16565b815250905092915050565b6143b161469b565b6143c560008361456290919063ffffffff16565b156143fb576143f46143ef836040518060200160405280600081525061431d90919063ffffffff16565b61457f565b9050614407565b6144048261457f565b90505b919050565b606082471015614451576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016144489061530c565b60405180910390fd5b61445a856145e9565b614499576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401614490906153ac565b60405180910390fd5b6000808673ffffffffffffffffffffffffffffffffffffffff1685876040516144c291906150b3565b60006040518083038185875af1925050503d80600081146144ff576040519150601f19603f3d011682016040523d82523d6000602084013e614504565b606091505b50915091506145148282866145fc565b92505050949350505050565b6000818361452e9190615862565b905092915050565b6000818361454491906156f1565b905092915050565b6000818361455a9190615656565b905092915050565b600061456d82614663565b60000151836000015112905092915050565b61458761469b565b6000826000015112156145cf576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016145c69061532c565b60405180910390fd5b604051806020016040528083600001518152509050919050565b600080823b905060008111915050919050565b6060831561460c5782905061465c565b60008351111561461f5782518084602001fd5b816040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161465391906152ca565b60405180910390fd5b9392505050565b61466b6146ae565b6040518060200160405280614691670de0b6b3a76400008561453690919063ffffffff16565b8152509050919050565b6040518060200160405280600081525090565b6040518060200160405280600081525090565b60006146d46146cf84615569565b615544565b905080838252602082019050828560208602820111156146f7576146f6615b3b565b5b60005b85811015614727578161470d88826148d5565b8452602084019350602083019250506001810190506146fa565b5050509392505050565b60008135905061474081615d6a565b92915050565b60008151905061475581615d6a565b92915050565b600082601f8301126147705761476f615b2c565b5b81516147808482602086016146c1565b91505092915050565b60008151905061479881615d81565b92915050565b6000815190506147ad81615d98565b92915050565b6000813590506147c281615daf565b92915050565b6000815190506147d781615daf565b92915050565b6000813590506147ec81615dc6565b92915050565b60008135905061480181615ddd565b92915050565b60008135905061481681615df4565b92915050565b60008135905061482b81615e0b565b92915050565b60008135905061484081615e22565b92915050565b60006060828403121561485c5761485b615b31565b5b81905092915050565b60006020828403121561487b5761487a615b31565b5b81905092915050565b60006020828403121561489a57614899615b36565b5b6148a46020615544565b905060006148b4848285016148c0565b60008301525092915050565b6000813590506148cf81615e32565b92915050565b6000815190506148e481615e32565b92915050565b6000813590506148f981615e49565b92915050565b60006020828403121561491557614914615b45565b5b600061492384828501614746565b91505092915050565b60006020828403121561494257614941615b45565b5b600082015167ffffffffffffffff8111156149605761495f615b40565b5b61496c8482850161475b565b91505092915050565b60006020828403121561498b5761498a615b45565b5b600061499984828501614789565b91505092915050565b6000602082840312156149b8576149b7615b45565b5b60006149c68482850161479e565b91505092915050565b6000602082840312156149e5576149e4615b45565b5b60006149f3848285016147b3565b91505092915050565b600060208284031215614a1257614a11615b45565b5b6000614a20848285016147c8565b91505092915050565b600080600080600060a08688031215614a4557614a44615b45565b5b6000614a53888289016147f2565b9550506020614a648882890161481c565b9450506040614a75888289016147dd565b9350506060614a86888289016147dd565b9250506080614a9788828901614731565b9150509295509295909350565b60008060008060008060008060006101a08a8c031215614ac757614ac6615b45565b5b6000614ad58c828d01614865565b9950506020614ae68c828d0161481c565b9850506040614af78c828d016148c0565b9750506060614b088c828d016148c0565b9650506080614b198c828d01614807565b95505060a0614b2a8c828d016148c0565b94505060c0614b3b8c828d01614846565b935050610120614b4d8c828d01614846565b925050610180614b5f8c828d01614831565b9150509295985092959850929598565b600060208284031215614b8557614b84615b45565b5b6000614b9384828501614884565b91505092915050565b600060208284031215614bb257614bb1615b45565b5b6000614bc0848285016148d5565b91505092915050565b60008060408385031215614be057614bdf615b45565b5b6000614bee858286016148d5565b9250506020614bff858286016148d5565b9150509250929050565b6000806000806000806000806000806101808b8d031215614c2d57614c2c615b45565b5b6000614c3b8d828e016148c0565b9a50506020614c4c8d828e016148c0565b9950506040614c5d8d828e01614807565b9850506060614c6e8d828e01614865565b9750506080614c7f8d828e0161481c565b96505060a0614c908d828e01614846565b955050610100614ca28d828e016148c0565b945050610120614cb48d828e016147dd565b935050610140614cc68d828e016147dd565b925050610160614cd88d828e016148c0565b9150509295989b9194979a5092959850565b6000806000806000806101008789031215614d0857614d07615b45565b5b6000614d1689828a016148c0565b9650506020614d2789828a016148c0565b9550506040614d3889828a0161481c565b9450506060614d4989828a01614807565b9350506080614d5a89828a016148c0565b92505060a0614d6b89828a01614846565b9150509295509295509295565b600080600060608486031215614d9157614d90615b45565b5b6000614d9f868287016148d5565b9350506020614db0868287016148d5565b9250506040614dc1868287016148d5565b9150509250925092565b600060208284031215614de157614de0615b45565b5b6000614def848285016148ea565b91505092915050565b6000614e048383614e10565b60208301905092915050565b614e19816158f6565b82525050565b614e28816158f6565b82525050565b6000614e39826155a5565b614e4381856155d3565b9350614e4e83615595565b8060005b83811015614e7f578151614e668882614df8565b9750614e71836155c6565b925050600181019050614e52565b5085935050505092915050565b614e9581615914565b82525050565b6000614ea6826155b0565b614eb081856155e4565b9350614ec08185602086016159dd565b80840191505092915050565b614ed5816159cb565b82525050565b6000614ee6826155bb565b614ef081856155ef565b9350614f008185602086016159dd565b614f0981615b4a565b840191505092915050565b6000614f216008836155ef565b9150614f2c82615b5b565b602082019050919050565b6000614f446026836155ef565b9150614f4f82615b84565b604082019050919050565b6000614f676017836155ef565b9150614f7282615bd3565b602082019050919050565b6000614f8a6012836155ef565b9150614f9582615bfc565b602082019050919050565b6000614fad600f836155ef565b9150614fb882615c25565b602082019050919050565b6000614fd06007836155ef565b9150614fdb82615c4e565b602082019050919050565b6000614ff3601d836155ef565b9150614ffe82615c77565b602082019050919050565b60006150166003836155ef565b915061502182615ca0565b602082019050919050565b6000615039602a836155ef565b915061504482615cc9565b604082019050919050565b600061505c6011836155ef565b915061506782615d18565b602082019050919050565b600061507f600c836155ef565b915061508a82615d41565b602082019050919050565b61509e816159b4565b82525050565b6150ad816159be565b82525050565b60006150bf8284614e9b565b915081905092915050565b60006020820190506150df6000830184614e1f565b92915050565b60006040820190506150fa6000830185614e1f565b6151076020830184614e1f565b9392505050565b60006060820190506151236000830186614e1f565b6151306020830185614e1f565b61513d6040830184615095565b949350505050565b600060e08201905061515a600083018a614e1f565b6151676020830189614e1f565b6151746040830188615095565b6151816060830187614ecc565b61518e6080830186614ecc565b61519b60a0830185614e1f565b6151a860c0830184615095565b98975050505050505050565b6000610100820190506151ca600083018b614e1f565b6151d7602083018a614e1f565b6151e46040830189615095565b6151f16060830188615095565b6151fe6080830187615095565b61520b60a0830186615095565b61521860c0830185614e1f565b61522560e0830184615095565b9998505050505050505050565b600060e082019050615247600083018a614e1f565b6152546020830189614e1f565b6152616040830188615095565b61526e6060830187615095565b61527b60808301866150a4565b61528860a0830185614e8c565b61529560c0830184614e8c565b98975050505050505050565b60006040820190506152b66000830185614e1f565b6152c36020830184615095565b9392505050565b600060208201905081810360008301526152e48184614edb565b905092915050565b6000602082019050818103600083015261530581614f14565b9050919050565b6000602082019050818103600083015261532581614f37565b9050919050565b6000602082019050818103600083015261534581614f5a565b9050919050565b6000602082019050818103600083015261536581614f7d565b9050919050565b6000602082019050818103600083015261538581614fa0565b9050919050565b600060208201905081810360008301526153a581614fc3565b9050919050565b600060208201905081810360008301526153c581614fe6565b9050919050565b600060208201905081810360008301526153e581615009565b9050919050565b600060208201905081810360008301526154058161502c565b9050919050565b600060208201905081810360008301526154258161504f565b9050919050565b6000602082019050818103600083015261544581615072565b9050919050565b60006020820190506154616000830184615095565b92915050565b600060a08201905061547c6000830188615095565b6154896020830187614ecc565b818103604083015261549b8186614e2e565b90506154aa6060830185614e1f565b6154b76080830184615095565b9695505050505050565b60006040820190506154d66000830185615095565b6154e36020830184615095565b9392505050565b600060a0820190506154ff6000830188615095565b61550c6020830187615095565b818103604083015261551e8186614e2e565b905061552d6060830185614e1f565b61553a6080830184615095565b9695505050505050565b600061554e61555f565b905061555a8282615a10565b919050565b6000604051905090565b600067ffffffffffffffff82111561558457615583615afd565b5b602082029050602081019050919050565b6000819050602082019050919050565b600081519050919050565b600081519050919050565b600081519050919050565b6000602082019050919050565b600082825260208201905092915050565b600081905092915050565b600082825260208201905092915050565b600061560b826159b4565b9150615616836159b4565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0382111561564b5761564a615a41565b5b828201905092915050565b60006156618261598a565b915061566c8361598a565b92508261567c5761567b615a70565b5b600160000383147f8000000000000000000000000000000000000000000000000000000000000000831416156156b5576156b4615a41565b5b828205905092915050565b60006156cb826159b4565b91506156d6836159b4565b9250826156e6576156e5615a70565b5b828204905092915050565b60006156fc8261598a565b91506157078361598a565b9250827f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048211600084136000841316161561574657615745615a41565b5b817f8000000000000000000000000000000000000000000000000000000000000000058312600084126000841316161561578357615782615a41565b5b827f800000000000000000000000000000000000000000000000000000000000000005821260008413600084121616156157c0576157bf615a41565b5b827f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff05821260008412600084121616156157fd576157fc615a41565b5b828202905092915050565b6000615813826159b4565b915061581e836159b4565b9250817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048311821515161561585757615856615a41565b5b828202905092915050565b600061586d8261598a565b91506158788361598a565b9250827f8000000000000000000000000000000000000000000000000000000000000000018212600084121516156158b3576158b2615a41565b5b827f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0182136000841216156158eb576158ea615a41565b5b828203905092915050565b600061590182615994565b9050919050565b60008115159050919050565b6000819050919050565b6000615929826158f6565b9050919050565b600061593b826158f6565b9050919050565b600061594d826158f6565b9050919050565b600061595f826158f6565b9050919050565b6000615971826158f6565b9050919050565b6000615983826158f6565b9050919050565b6000819050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b600060ff82169050919050565b60006159d6826159b4565b9050919050565b60005b838110156159fb5780820151818401526020810190506159e0565b83811115615a0a576000848401525b50505050565b615a1982615b4a565b810181811067ffffffffffffffff82111715615a3857615a37615afd565b5b80604052505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f534c495050414745000000000000000000000000000000000000000000000000600082015250565b7f416464726573733a20696e73756666696369656e742062616c616e636520666f60008201527f722063616c6c0000000000000000000000000000000000000000000000000000602082015250565b7f4e656761746976652076616c75652070726f7669646564000000000000000000600082015250565b7f556e7369676e656420746f6f206c617267650000000000000000000000000000600082015250565b7f4e6f2073796e746820706f6f6c65640000000000000000000000000000000000600082015250565b7f4558504952454400000000000000000000000000000000000000000000000000600082015250565b7f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000600082015250565b7f4255470000000000000000000000000000000000000000000000000000000000600082015250565b7f5361666545524332303a204552433230206f7065726174696f6e20646964206e60008201527f6f74207375636365656400000000000000000000000000000000000000000000602082015250565b7f494e56414c494420415247554d454e5453000000000000000000000000000000600082015250565b7f554e50524f46495441424c450000000000000000000000000000000000000000600082015250565b615d73816158f6565b8114615d7e57600080fd5b50565b615d8a81615908565b8114615d9557600080fd5b50565b615da18161591e565b8114615dac57600080fd5b50565b615db881615930565b8114615dc357600080fd5b50565b615dcf81615942565b8114615dda57600080fd5b50565b615de681615954565b8114615df157600080fd5b50565b615dfd81615966565b8114615e0857600080fd5b50565b615e1481615978565b8114615e1f57600080fd5b50565b60038110615e2f57600080fd5b50565b615e3b816159b4565b8114615e4657600080fd5b50565b615e52816159be565b8114615e5d57600080fd5b5056fea264697066735822122071cc5aa7eff48ea4753b14b9677e2ab164fd1217735bdff2b048531410a0966464736f6c63430008060033