文件 1 的 1:Pool.sol
pragma solidity ^0.5.17;
pragma experimental ABIEncoderV2;
library SafeMath {
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
return sub(a, b, "SafeMath: subtraction overflow");
}
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b <= a, errorMessage);
uint256 c = a - b;
return c;
}
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
uint256 c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
function div(uint256 a, uint256 b) internal pure returns (uint256) {
return div(a, b, "SafeMath: division by zero");
}
function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b > 0, errorMessage);
uint256 c = a / b;
return c;
}
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
return mod(a, b, "SafeMath: modulo by zero");
}
function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b != 0, errorMessage);
return a % b;
}
}
interface IERC20 {
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address recipient, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
}
library Require {
uint256 constant ASCII_ZERO = 48;
uint256 constant ASCII_RELATIVE_ZERO = 87;
uint256 constant ASCII_LOWER_EX = 120;
bytes2 constant COLON = 0x3a20;
bytes2 constant COMMA = 0x2c20;
bytes2 constant LPAREN = 0x203c;
byte constant RPAREN = 0x3e;
uint256 constant FOUR_BIT_MASK = 0xf;
function that(
bool must,
bytes32 file,
bytes32 reason
)
internal
pure
{
if (!must) {
revert(
string(
abi.encodePacked(
stringifyTruncated(file),
COLON,
stringifyTruncated(reason)
)
)
);
}
}
function that(
bool must,
bytes32 file,
bytes32 reason,
uint256 payloadA
)
internal
pure
{
if (!must) {
revert(
string(
abi.encodePacked(
stringifyTruncated(file),
COLON,
stringifyTruncated(reason),
LPAREN,
stringify(payloadA),
RPAREN
)
)
);
}
}
function that(
bool must,
bytes32 file,
bytes32 reason,
uint256 payloadA,
uint256 payloadB
)
internal
pure
{
if (!must) {
revert(
string(
abi.encodePacked(
stringifyTruncated(file),
COLON,
stringifyTruncated(reason),
LPAREN,
stringify(payloadA),
COMMA,
stringify(payloadB),
RPAREN
)
)
);
}
}
function that(
bool must,
bytes32 file,
bytes32 reason,
address payloadA
)
internal
pure
{
if (!must) {
revert(
string(
abi.encodePacked(
stringifyTruncated(file),
COLON,
stringifyTruncated(reason),
LPAREN,
stringify(payloadA),
RPAREN
)
)
);
}
}
function that(
bool must,
bytes32 file,
bytes32 reason,
address payloadA,
uint256 payloadB
)
internal
pure
{
if (!must) {
revert(
string(
abi.encodePacked(
stringifyTruncated(file),
COLON,
stringifyTruncated(reason),
LPAREN,
stringify(payloadA),
COMMA,
stringify(payloadB),
RPAREN
)
)
);
}
}
function that(
bool must,
bytes32 file,
bytes32 reason,
address payloadA,
uint256 payloadB,
uint256 payloadC
)
internal
pure
{
if (!must) {
revert(
string(
abi.encodePacked(
stringifyTruncated(file),
COLON,
stringifyTruncated(reason),
LPAREN,
stringify(payloadA),
COMMA,
stringify(payloadB),
COMMA,
stringify(payloadC),
RPAREN
)
)
);
}
}
function that(
bool must,
bytes32 file,
bytes32 reason,
bytes32 payloadA
)
internal
pure
{
if (!must) {
revert(
string(
abi.encodePacked(
stringifyTruncated(file),
COLON,
stringifyTruncated(reason),
LPAREN,
stringify(payloadA),
RPAREN
)
)
);
}
}
function that(
bool must,
bytes32 file,
bytes32 reason,
bytes32 payloadA,
uint256 payloadB,
uint256 payloadC
)
internal
pure
{
if (!must) {
revert(
string(
abi.encodePacked(
stringifyTruncated(file),
COLON,
stringifyTruncated(reason),
LPAREN,
stringify(payloadA),
COMMA,
stringify(payloadB),
COMMA,
stringify(payloadC),
RPAREN
)
)
);
}
}
function stringifyTruncated(
bytes32 input
)
private
pure
returns (bytes memory)
{
bytes memory result = abi.encodePacked(input);
for (uint256 i = 32; i > 0; ) {
i--;
if (result[i] != 0) {
uint256 length = i + 1;
assembly {
mstore(result, length)
}
return result;
}
}
return new bytes(0);
}
function stringify(
uint256 input
)
private
pure
returns (bytes memory)
{
if (input == 0) {
return "0";
}
uint256 j = input;
uint256 length;
while (j != 0) {
length++;
j /= 10;
}
bytes memory bstr = new bytes(length);
j = input;
for (uint256 i = length; i > 0; ) {
i--;
bstr[i] = byte(uint8(ASCII_ZERO + (j % 10)));
j /= 10;
}
return bstr;
}
function stringify(
address input
)
private
pure
returns (bytes memory)
{
uint256 z = uint256(input);
bytes memory result = new bytes(42);
result[0] = byte(uint8(ASCII_ZERO));
result[1] = byte(uint8(ASCII_LOWER_EX));
for (uint256 i = 0; i < 20; i++) {
uint256 shift = i * 2;
result[41 - shift] = char(z & FOUR_BIT_MASK);
z = z >> 4;
result[40 - shift] = char(z & FOUR_BIT_MASK);
z = z >> 4;
}
return result;
}
function stringify(
bytes32 input
)
private
pure
returns (bytes memory)
{
uint256 z = uint256(input);
bytes memory result = new bytes(66);
result[0] = byte(uint8(ASCII_ZERO));
result[1] = byte(uint8(ASCII_LOWER_EX));
for (uint256 i = 0; i < 32; i++) {
uint256 shift = i * 2;
result[65 - shift] = char(z & FOUR_BIT_MASK);
z = z >> 4;
result[64 - shift] = char(z & FOUR_BIT_MASK);
z = z >> 4;
}
return result;
}
function char(
uint256 input
)
private
pure
returns (byte)
{
if (input < 10) {
return byte(uint8(input + ASCII_ZERO));
}
return byte(uint8(input + ASCII_RELATIVE_ZERO));
}
}
library Decimal {
using SafeMath for uint256;
uint256 constant BASE = 10**18;
struct D256 {
uint256 value;
}
function zero()
internal
pure
returns (D256 memory)
{
return D256({ value: 0 });
}
function one()
internal
pure
returns (D256 memory)
{
return D256({ value: BASE });
}
function from(
uint256 a
)
internal
pure
returns (D256 memory)
{
return D256({ value: a.mul(BASE) });
}
function ratio(
uint256 a,
uint256 b
)
internal
pure
returns (D256 memory)
{
return D256({ value: getPartial(a, BASE, b) });
}
function add(
D256 memory self,
uint256 b
)
internal
pure
returns (D256 memory)
{
return D256({ value: self.value.add(b.mul(BASE)) });
}
function sub(
D256 memory self,
uint256 b
)
internal
pure
returns (D256 memory)
{
return D256({ value: self.value.sub(b.mul(BASE)) });
}
function sub(
D256 memory self,
uint256 b,
string memory reason
)
internal
pure
returns (D256 memory)
{
return D256({ value: self.value.sub(b.mul(BASE), reason) });
}
function mul(
D256 memory self,
uint256 b
)
internal
pure
returns (D256 memory)
{
return D256({ value: self.value.mul(b) });
}
function div(
D256 memory self,
uint256 b
)
internal
pure
returns (D256 memory)
{
return D256({ value: self.value.div(b) });
}
function pow(
D256 memory self,
uint256 b
)
internal
pure
returns (D256 memory)
{
if (b == 0) {
return from(1);
}
D256 memory temp = D256({ value: self.value });
for (uint256 i = 1; i < b; i++) {
temp = mul(temp, self);
}
return temp;
}
function add(
D256 memory self,
D256 memory b
)
internal
pure
returns (D256 memory)
{
return D256({ value: self.value.add(b.value) });
}
function sub(
D256 memory self,
D256 memory b
)
internal
pure
returns (D256 memory)
{
return D256({ value: self.value.sub(b.value) });
}
function sub(
D256 memory self,
D256 memory b,
string memory reason
)
internal
pure
returns (D256 memory)
{
return D256({ value: self.value.sub(b.value, reason) });
}
function mul(
D256 memory self,
D256 memory b
)
internal
pure
returns (D256 memory)
{
return D256({ value: getPartial(self.value, b.value, BASE) });
}
function div(
D256 memory self,
D256 memory b
)
internal
pure
returns (D256 memory)
{
return D256({ value: getPartial(self.value, BASE, b.value) });
}
function equals(D256 memory self, D256 memory b) internal pure returns (bool) {
return self.value == b.value;
}
function greaterThan(D256 memory self, D256 memory b) internal pure returns (bool) {
return compareTo(self, b) == 2;
}
function lessThan(D256 memory self, D256 memory b) internal pure returns (bool) {
return compareTo(self, b) == 0;
}
function greaterThanOrEqualTo(D256 memory self, D256 memory b) internal pure returns (bool) {
return compareTo(self, b) > 0;
}
function lessThanOrEqualTo(D256 memory self, D256 memory b) internal pure returns (bool) {
return compareTo(self, b) < 2;
}
function isZero(D256 memory self) internal pure returns (bool) {
return self.value == 0;
}
function asUint256(D256 memory self) internal pure returns (uint256) {
return self.value.div(BASE);
}
function getPartial(
uint256 target,
uint256 numerator,
uint256 denominator
)
private
pure
returns (uint256)
{
return target.mul(numerator).div(denominator);
}
function compareTo(
D256 memory a,
D256 memory b
)
private
pure
returns (uint256)
{
if (a.value == b.value) {
return 1;
}
return a.value > b.value ? 2 : 0;
}
}
library Constants {
uint256 private constant CHAIN_ID = 1;
uint256 private constant BOOTSTRAPPING_PERIOD = 56;
uint256 private constant BOOTSTRAPPING_PRICE = 11e17;
address private constant sXAU = address(0x261EfCdD24CeA98652B9700800a13DfBca4103fF);
uint256 private constant ORACLE_RESERVE_MINIMUM = 1e18;
uint256 private constant INITIAL_STAKE_MULTIPLE = 1e6;
struct EpochStrategy {
uint256 offset;
uint256 start;
uint256 period;
}
uint256 private constant EPOCH_START = 1609027200;
uint256 private constant EPOCH_OFFSET = 0;
uint256 private constant EPOCH_PERIOD = 21600;
uint256 private constant GOVERNANCE_PERIOD = 9;
uint256 private constant GOVERNANCE_EXPIRATION = 2;
uint256 private constant GOVERNANCE_QUORUM = 20e16;
uint256 private constant GOVERNANCE_PROPOSAL_THRESHOLD = 5e15;
uint256 private constant GOVERNANCE_SUPER_MAJORITY = 66e16;
uint256 private constant GOVERNANCE_EMERGENCY_DELAY = 6;
uint256 private constant ADVANCE_INCENTIVE = 1e17;
uint256 private constant DAO_EXIT_LOCKUP_EPOCHS = 20;
uint256 private constant POOL_EXIT_LOCKUP_EPOCHS = 8;
uint256 private constant COUPON_EXPIRATION = 120;
uint256 private constant DEBT_RATIO_CAP = 35e16;
uint256 private constant SUPPLY_CHANGE_LIMIT = 1e17;
uint256 private constant COUPON_SUPPLY_CHANGE_LIMIT = 6e16;
uint256 private constant ORACLE_POOL_RATIO = 20;
uint256 private constant TREASURY_RATIO = 250;
address private constant TREASURY_ADDRESS = address(0x0000000000000000000000000000000000000000);
function getSXAUAddress() internal pure returns (address) {
return sXAU;
}
function getOracleReserveMinimum() internal pure returns (uint256) {
return ORACLE_RESERVE_MINIMUM;
}
function getCurrentEpochStrategy() internal pure returns (EpochStrategy memory) {
return EpochStrategy({
offset: EPOCH_OFFSET,
start: EPOCH_START,
period: EPOCH_PERIOD
});
}
function getInitialStakeMultiple() internal pure returns (uint256) {
return INITIAL_STAKE_MULTIPLE;
}
function getBootstrappingPeriod() internal pure returns (uint256) {
return BOOTSTRAPPING_PERIOD;
}
function getBootstrappingPrice() internal pure returns (Decimal.D256 memory) {
return Decimal.D256({value: BOOTSTRAPPING_PRICE});
}
function getGovernancePeriod() internal pure returns (uint256) {
return GOVERNANCE_PERIOD;
}
function getGovernanceExpiration() internal pure returns (uint256) {
return GOVERNANCE_EXPIRATION;
}
function getGovernanceQuorum() internal pure returns (Decimal.D256 memory) {
return Decimal.D256({value: GOVERNANCE_QUORUM});
}
function getGovernanceProposalThreshold() internal pure returns (Decimal.D256 memory) {
return Decimal.D256({value: GOVERNANCE_PROPOSAL_THRESHOLD});
}
function getGovernanceSuperMajority() internal pure returns (Decimal.D256 memory) {
return Decimal.D256({value: GOVERNANCE_SUPER_MAJORITY});
}
function getGovernanceEmergencyDelay() internal pure returns (uint256) {
return GOVERNANCE_EMERGENCY_DELAY;
}
function getAdvanceIncentive() internal pure returns (uint256) {
return ADVANCE_INCENTIVE;
}
function getDAOExitLockupEpochs() internal pure returns (uint256) {
return DAO_EXIT_LOCKUP_EPOCHS;
}
function getPoolExitLockupEpochs() internal pure returns (uint256) {
return POOL_EXIT_LOCKUP_EPOCHS;
}
function getCouponExpiration() internal pure returns (uint256) {
return COUPON_EXPIRATION;
}
function getDebtRatioCap() internal pure returns (Decimal.D256 memory) {
return Decimal.D256({value: DEBT_RATIO_CAP});
}
function getSupplyChangeLimit() internal pure returns (Decimal.D256 memory) {
return Decimal.D256({value: SUPPLY_CHANGE_LIMIT});
}
function getCouponSupplyChangeLimit() internal pure returns (Decimal.D256 memory) {
return Decimal.D256({value: COUPON_SUPPLY_CHANGE_LIMIT});
}
function getOraclePoolRatio() internal pure returns (uint256) {
return ORACLE_POOL_RATIO;
}
function getTreasuryRatio() internal pure returns (uint256) {
return TREASURY_RATIO;
}
function getChainId() internal pure returns (uint256) {
return CHAIN_ID;
}
function getTreasuryAddress() internal pure returns (address) {
return TREASURY_ADDRESS;
}
}
contract IGold is IERC20 {
function burn(uint256 amount) public;
function burnFrom(address account, uint256 amount) public;
function mint(address account, uint256 amount) public returns (bool);
}
contract IDAO {
function epoch() external view returns (uint256);
}
contract PoolAccount {
enum Status {
Frozen,
Fluid,
Locked
}
struct State {
uint256 staged;
uint256 claimable;
uint256 bonded;
uint256 phantom;
uint256 fluidUntil;
}
}
contract PoolStorage {
struct Provider {
IDAO dao;
IGold gold;
IERC20 univ2;
}
struct Balance {
uint256 staged;
uint256 claimable;
uint256 bonded;
uint256 phantom;
}
struct State {
Balance balance;
Provider provider;
bool paused;
mapping(address => PoolAccount.State) accounts;
}
}
contract PoolState {
PoolStorage.State _state;
}
contract PoolGetters is PoolState {
using SafeMath for uint256;
function sXAU() public view returns (address) {
return Constants.getSXAUAddress();
}
function dao() public view returns (IDAO) {
return _state.provider.dao;
}
function gold() public view returns (IGold) {
return _state.provider.gold;
}
function univ2() public view returns (IERC20) {
return _state.provider.univ2;
}
function totalBonded() public view returns (uint256) {
return _state.balance.bonded;
}
function totalStaged() public view returns (uint256) {
return _state.balance.staged;
}
function totalClaimable() public view returns (uint256) {
return _state.balance.claimable;
}
function totalPhantom() public view returns (uint256) {
return _state.balance.phantom;
}
function totalRewarded(IGold gold) public view returns (uint256) {
return gold.balanceOf(address(this)).sub(totalClaimable());
}
function paused() public view returns (bool) {
return _state.paused;
}
function balanceOfStaged(address account) public view returns (uint256) {
return _state.accounts[account].staged;
}
function balanceOfClaimable(address account) public view returns (uint256) {
return _state.accounts[account].claimable;
}
function balanceOfBonded(address account) public view returns (uint256) {
return _state.accounts[account].bonded;
}
function balanceOfPhantom(address account) public view returns (uint256) {
return _state.accounts[account].phantom;
}
function balanceOfRewarded(address account, IGold gold) public view returns (uint256) {
uint256 totalBonded = totalBonded();
if (totalBonded == 0) {
return 0;
}
uint256 totalRewardedWithPhantom = totalRewarded(gold).add(totalPhantom());
uint256 balanceOfRewardedWithPhantom = totalRewardedWithPhantom
.mul(balanceOfBonded(account))
.div(totalBonded);
uint256 balanceOfPhantom = balanceOfPhantom(account);
if (balanceOfRewardedWithPhantom > balanceOfPhantom) {
return balanceOfRewardedWithPhantom.sub(balanceOfPhantom);
}
return 0;
}
function statusOf(address account, uint256 epoch) public view returns (PoolAccount.Status) {
return epoch >= _state.accounts[account].fluidUntil ?
PoolAccount.Status.Frozen :
PoolAccount.Status.Fluid;
}
}
contract PoolSetters is PoolState, PoolGetters {
using SafeMath for uint256;
function pause() internal {
_state.paused = true;
}
function incrementBalanceOfBonded(address account, uint256 amount) internal {
_state.accounts[account].bonded = _state.accounts[account].bonded.add(amount);
_state.balance.bonded = _state.balance.bonded.add(amount);
}
function decrementBalanceOfBonded(address account, uint256 amount, string memory reason) internal {
_state.accounts[account].bonded = _state.accounts[account].bonded.sub(amount, reason);
_state.balance.bonded = _state.balance.bonded.sub(amount, reason);
}
function incrementBalanceOfStaged(address account, uint256 amount) internal {
_state.accounts[account].staged = _state.accounts[account].staged.add(amount);
_state.balance.staged = _state.balance.staged.add(amount);
}
function decrementBalanceOfStaged(address account, uint256 amount, string memory reason) internal {
_state.accounts[account].staged = _state.accounts[account].staged.sub(amount, reason);
_state.balance.staged = _state.balance.staged.sub(amount, reason);
}
function incrementBalanceOfClaimable(address account, uint256 amount) internal {
_state.accounts[account].claimable = _state.accounts[account].claimable.add(amount);
_state.balance.claimable = _state.balance.claimable.add(amount);
}
function decrementBalanceOfClaimable(address account, uint256 amount, string memory reason) internal {
_state.accounts[account].claimable = _state.accounts[account].claimable.sub(amount, reason);
_state.balance.claimable = _state.balance.claimable.sub(amount, reason);
}
function incrementBalanceOfPhantom(address account, uint256 amount) internal {
_state.accounts[account].phantom = _state.accounts[account].phantom.add(amount);
_state.balance.phantom = _state.balance.phantom.add(amount);
}
function decrementBalanceOfPhantom(address account, uint256 amount, string memory reason) internal {
_state.accounts[account].phantom = _state.accounts[account].phantom.sub(amount, reason);
_state.balance.phantom = _state.balance.phantom.sub(amount, reason);
}
function unfreeze(address account, uint256 epoch) internal {
_state.accounts[account].fluidUntil = epoch.add(Constants.getPoolExitLockupEpochs());
}
}
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;
}
library UniswapV2Library {
using SafeMath for uint;
function sortTokens(address tokenA, address tokenB) internal pure returns (address token0, address token1) {
require(tokenA != tokenB, 'UniswapV2Library: IDENTICAL_ADDRESSES');
(token0, token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA);
require(token0 != address(0), 'UniswapV2Library: ZERO_ADDRESS');
}
function pairFor(address factory, address tokenA, address tokenB) internal pure returns (address pair) {
(address token0, address token1) = sortTokens(tokenA, tokenB);
pair = address(uint(keccak256(abi.encodePacked(
hex'ff',
factory,
keccak256(abi.encodePacked(token0, token1)),
hex'96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f'
))));
}
function getReserves(address factory, address tokenA, address tokenB) internal view returns (uint reserveA, uint reserveB) {
(address token0,) = sortTokens(tokenA, tokenB);
(uint reserve0, uint reserve1,) = IUniswapV2Pair(pairFor(factory, tokenA, tokenB)).getReserves();
(reserveA, reserveB) = tokenA == token0 ? (reserve0, reserve1) : (reserve1, reserve0);
}
function quote(uint amountA, uint reserveA, uint reserveB) internal pure returns (uint amountB) {
require(amountA > 0, 'UniswapV2Library: INSUFFICIENT_AMOUNT');
require(reserveA > 0 && reserveB > 0, 'UniswapV2Library: INSUFFICIENT_LIQUIDITY');
amountB = amountA.mul(reserveB) / reserveA;
}
}
contract Pool is PoolSetters {
using SafeMath for uint256;
constructor(address gold, address univ2) public {
_state.provider.dao = IDAO(msg.sender);
_state.provider.gold = IGold(gold);
_state.provider.univ2 = IERC20(univ2);
}
address private constant UNISWAP_FACTORY = address(0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f);
function addLiquidity(uint256 goldAmount) internal returns (uint256, uint256) {
(address gold, address sXAU) = (address(_state.provider.gold), sXAU());
(uint reserveA, uint reserveB) = getReserves(gold, sXAU);
uint256 sXAUAmount = (reserveA == 0 && reserveB == 0) ?
goldAmount :
UniswapV2Library.quote(goldAmount, reserveA, reserveB);
address pair = address(_state.provider.univ2);
IERC20(gold).transfer(pair, goldAmount);
IERC20(sXAU).transferFrom(msg.sender, pair, sXAUAmount);
return (sXAUAmount, IUniswapV2Pair(pair).mint(address(this)));
}
function getReserves(address tokenA, address tokenB) internal view returns (uint reserveA, uint reserveB) {
(address token0,) = UniswapV2Library.sortTokens(tokenA, tokenB);
(uint reserve0, uint reserve1,) = IUniswapV2Pair(UniswapV2Library.pairFor(UNISWAP_FACTORY, tokenA, tokenB)).getReserves();
(reserveA, reserveB) = tokenA == token0 ? (reserve0, reserve1) : (reserve1, reserve0);
}
bytes32 private constant FILE = "Pool";
event Deposit(address indexed account, uint256 value);
event Withdraw(address indexed account, uint256 value);
event Claim(address indexed account, uint256 value);
event Bond(address indexed account, uint256 start, uint256 value);
event Unbond(address indexed account, uint256 start, uint256 value, uint256 newClaimable);
event Provide(address indexed account, uint256 value, uint256 lessSXAU, uint256 newUniv2);
function deposit(uint256 value) external onlyFrozen(msg.sender) notPaused {
_state.provider.univ2.transferFrom(msg.sender, address(this), value);
incrementBalanceOfStaged(msg.sender, value);
balanceCheck();
emit Deposit(msg.sender, value);
}
function withdraw(uint256 value) external onlyFrozen(msg.sender) {
_state.provider.univ2.transfer(msg.sender, value);
decrementBalanceOfStaged(msg.sender, value, "Pool: insufficient staged balance");
balanceCheck();
emit Withdraw(msg.sender, value);
}
function claim(uint256 value) external onlyFrozen(msg.sender) {
_state.provider.gold.transfer(msg.sender, value);
decrementBalanceOfClaimable(msg.sender, value, "Pool: insufficient claimable balance");
balanceCheck();
emit Claim(msg.sender, value);
}
function unfreeze(address account) internal {
super.unfreeze(account, _state.provider.dao.epoch());
}
function bond(uint256 value) external notPaused {
unfreeze(msg.sender);
uint256 totalRewardedWithPhantom = totalRewarded(_state.provider.gold).add(totalPhantom());
uint256 newPhantom = totalBonded() == 0 ?
totalRewarded(_state.provider.gold) == 0 ? Constants.getInitialStakeMultiple().mul(value) : 0 :
totalRewardedWithPhantom.mul(value).div(totalBonded());
incrementBalanceOfBonded(msg.sender, value);
incrementBalanceOfPhantom(msg.sender, newPhantom);
decrementBalanceOfStaged(msg.sender, value, "Pool: insufficient staged balance");
balanceCheck();
emit Bond(msg.sender, _state.provider.dao.epoch().add(1), value);
}
function unbond(uint256 value) external {
unfreeze(msg.sender);
uint256 balanceOfBonded = balanceOfBonded(msg.sender);
Require.that(
balanceOfBonded > 0,
FILE,
"insufficient bonded balance"
);
uint256 newClaimable = balanceOfRewarded(msg.sender, _state.provider.gold).mul(value).div(balanceOfBonded);
uint256 lessPhantom = balanceOfPhantom(msg.sender).mul(value).div(balanceOfBonded);
incrementBalanceOfStaged(msg.sender, value);
incrementBalanceOfClaimable(msg.sender, newClaimable);
decrementBalanceOfBonded(msg.sender, value, "Pool: insufficient bonded balance");
decrementBalanceOfPhantom(msg.sender, lessPhantom, "Pool: insufficient phantom balance");
balanceCheck();
emit Unbond(msg.sender, _state.provider.dao.epoch().add(1), value, newClaimable);
}
function provide(uint256 value) external onlyFrozen(msg.sender) notPaused {
Require.that(
totalBonded() > 0,
FILE,
"insufficient total bonded"
);
Require.that(
totalRewarded(_state.provider.gold) > 0,
FILE,
"insufficient total rewarded"
);
Require.that(
balanceOfRewarded(msg.sender, _state.provider.gold) >= value,
FILE,
"insufficient rewarded balance"
);
(uint256 lessSXAU, uint256 newUniv2) = addLiquidity(value);
uint256 totalRewardedWithPhantom = totalRewarded(_state.provider.gold).add(totalPhantom()).add(value);
uint256 newPhantomFromBonded = totalRewardedWithPhantom.mul(newUniv2).div(totalBonded());
incrementBalanceOfBonded(msg.sender, newUniv2);
incrementBalanceOfPhantom(msg.sender, value.add(newPhantomFromBonded));
balanceCheck();
emit Provide(msg.sender, value, lessSXAU, newUniv2);
}
function emergencyWithdraw(address token, uint256 value) external onlyDao {
IERC20(token).transfer(address(_state.provider.dao), value);
}
function emergencyPause() external onlyDao {
pause();
}
function balanceCheck() private {
Require.that(
_state.provider.univ2.balanceOf(address(this)) >= totalStaged().add(totalBonded()),
FILE,
"Inconsistent UNI-V2 balances"
);
}
modifier onlyFrozen(address account) {
Require.that(
statusOf(account, _state.provider.dao.epoch()) == PoolAccount.Status.Frozen,
FILE,
"Not frozen"
);
_;
}
modifier onlyDao() {
Require.that(
msg.sender == address(_state.provider.dao),
FILE,
"Not dao"
);
_;
}
modifier notPaused() {
Require.that(
!paused(),
FILE,
"Paused"
);
_;
}
}