账户
0x1d...c10c
cyUSD

cyUSD

$500
此合同的源代码已经过验证!
合同元数据
编译器
0.5.17+commit.d19bba13
语言
Solidity
合同源代码
文件 1 的 3:creamY.sol
pragma solidity 0.5.17;

import './safeMath.sol';
import './normalizer.sol';

interface IERC20 {
    function totalSupply() external view returns (uint);
    function balanceOf(address account) external view returns (uint);
    function transfer(address recipient, uint amount) external returns (bool);
    function allowance(address owner, address spender) external view returns (uint);
    function approve(address spender, uint amount) external returns (bool);
    function transferFrom(address sender, address recipient, uint amount) external returns (bool);
    event Transfer(address indexed from, address indexed to, uint value);
    event Approval(address indexed owner, address indexed spender, uint value);
}

contract Context {
    constructor () internal { }
    // solhint-disable-previous-line no-empty-blocks

    function _msgSender() internal view returns (address payable) {
        return msg.sender;
    }
}

contract ERC20 is Context, IERC20 {
    using SafeMath for uint;

    mapping (address => uint) private _balances;

    mapping (address => mapping (address => uint)) private _allowances;

    uint private _totalSupply;
    function totalSupply() public view returns (uint) {
        return _totalSupply;
    }
    function balanceOf(address account) public view returns (uint) {
        return _balances[account];
    }
    function transfer(address recipient, uint amount) public returns (bool) {
        _transfer(_msgSender(), recipient, amount);
        return true;
    }
    function allowance(address owner, address spender) public view returns (uint) {
        return _allowances[owner][spender];
    }
    function approve(address spender, uint amount) public returns (bool) {
        _approve(_msgSender(), spender, amount);
        return true;
    }
    function transferFrom(address sender, address recipient, uint amount) public returns (bool) {
        _transfer(sender, recipient, amount);
        _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance"));
        return true;
    }
    function increaseAllowance(address spender, uint addedValue) public returns (bool) {
        _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue));
        return true;
    }
    function decreaseAllowance(address spender, uint subtractedValue) public returns (bool) {
        _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero"));
        return true;
    }
    function _transfer(address sender, address recipient, uint amount) internal {
        require(sender != address(0), "ERC20: transfer from the zero address");
        require(recipient != address(0), "ERC20: transfer to the zero address");

        _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance");
        _balances[recipient] = _balances[recipient].add(amount);
        emit Transfer(sender, recipient, amount);
    }
    function _mint(address account, uint amount) internal {
        require(account != address(0), "ERC20: mint to the zero address");

        _totalSupply = _totalSupply.add(amount);
        _balances[account] = _balances[account].add(amount);
        emit Transfer(address(0), account, amount);
    }
    function _burn(address account, uint amount) internal {
        require(account != address(0), "ERC20: burn from the zero address");

        _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance");
        _totalSupply = _totalSupply.sub(amount);
        emit Transfer(account, address(0), amount);
    }
    function _approve(address owner, address spender, uint amount) internal {
        require(owner != address(0), "ERC20: approve from the zero address");
        require(spender != address(0), "ERC20: approve to the zero address");

        _allowances[owner][spender] = amount;
        emit Approval(owner, spender, amount);
    }
}

contract ERC20Detailed is IERC20 {
    string private _name;
    string private _symbol;
    uint8 private _decimals;

    constructor (string memory name, string memory symbol, uint8 decimals) public {
        _name = name;
        _symbol = symbol;
        _decimals = decimals;
    }
    function name() public view returns (string memory) {
        return _name;
    }
    function symbol() public view returns (string memory) {
        return _symbol;
    }
    function decimals() public view returns (uint8) {
        return _decimals;
    }
}

library Address {
    function isContract(address account) internal view returns (bool) {
        bytes32 codehash;
        bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
        // solhint-disable-next-line no-inline-assembly
        assembly { codehash := extcodehash(account) }
        return (codehash != 0x0 && codehash != accountHash);
    }
}

library SafeERC20 {
    using SafeMath for uint;
    using Address for address;

    function safeTransfer(IERC20 token, address to, uint value) internal {
        callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
    }

    function safeTransferFrom(IERC20 token, address from, address to, uint value) internal {
        callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
    }

    function safeApprove(IERC20 token, address spender, uint value) internal {
        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 callOptionalReturn(IERC20 token, bytes memory data) private {
        require(address(token).isContract(), "SafeERC20: call to non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = address(token).call(data);
        require(success, "SafeERC20: low-level call failed");

        if (returndata.length > 0) { // Return data is optional
            // solhint-disable-next-line max-line-length
            require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
        }
    }
}

library SignedSafeMath {
    int256 constant private _INT256_MIN = -2**255;
    function mul(int256 a, int256 b) internal pure returns (int256) {
        if (a == 0) {
            return 0;
        }

        require(!(a == -1 && b == _INT256_MIN), "SignedSafeMath: multiplication overflow");

        int256 c = a * b;
        require(c / a == b, "SignedSafeMath: multiplication overflow");

        return c;
    }
    function div(int256 a, int256 b) internal pure returns (int256) {
        require(b != 0, "SignedSafeMath: division by zero");
        require(!(b == -1 && a == _INT256_MIN), "SignedSafeMath: division overflow");

        int256 c = a / b;

        return c;
    }
    function sub(int256 a, int256 b) internal pure returns (int256) {
        int256 c = a - b;
        require((b >= 0 && c <= a) || (b < 0 && c > a), "SignedSafeMath: subtraction overflow");

        return c;
    }
    function add(int256 a, int256 b) internal pure returns (int256) {
        int256 c = a + b;
        require((b >= 0 && c >= a) || (b < 0 && c < a), "SignedSafeMath: addition overflow");

        return c;
    }
    function sqrt(int256 x) internal pure returns (int256) {
        int256 z = add(x / 2, 1);
        int256 y = x;
        while (z < y)
        {
            y = z;
            z = ((add((x / z), z)) / 2);
        }
        return y;
    }
}

contract CreamY is ERC20, ERC20Detailed {

    event LOG_SWAP(
        address indexed caller,
        address indexed tokenIn,
        address indexed tokenOut,
        uint            tokenAmountIn,
        uint            tokenAmountOut
    );

    event LOG_JOIN(
        address indexed caller,
        address indexed tokenIn,
        uint            tokenAmountIn
    );

    event LOG_EXIT(
        address indexed caller,
        address indexed tokenOut,
        uint            tokenAmountOut
    );

    using SafeMath for uint;
    using SignedSafeMath for int256;
    using SafeERC20 for IERC20;

    mapping(address => bool) public coins;
    mapping(address => bool) public pause;
    IERC20[] public allCoins;
    Normalizer public normalizer;
    address public governance;
    address public reservePool;

    constructor(address _normalizer, address _reservePool) public ERC20Detailed("CreamY USD", "cyUSD", 18) {
        governance = msg.sender;
        normalizer = Normalizer(_normalizer);
        reservePool = _reservePool;
    }

    function setGovernance(address _governance) external {
        require(msg.sender == governance, "!governance");
        governance = _governance;
    }

    function setNormalizer(address _normalizer) external {
        require(msg.sender == governance, "!governance");
        normalizer = Normalizer(_normalizer);
    }

    function setReservePool(address _reservePool) external {
        require(msg.sender == governance, "!governance");
        require(_reservePool != address(0), "invalid reserve pool");
        reservePool = _reservePool;
    }

    function setFees(uint _fee, uint _reserveRatio) external {
        require(msg.sender == governance, '!governance');
        require(_fee < 1e18 && _fee >= 0.99e18, 'Invalid fee'); // 0 < fee <= 1%
        if (_reserveRatio > 0) {
            require(_reserveRatio <= 1e18, 'Invalid reserve ratio'); // reserve ratio <= 100% fee
        }
        fee = _fee;
        reserveRatio = _reserveRatio;
    }

    function approveCoins(address _coin) external {
        require(msg.sender == governance, "!governance");
        require(coins[_coin] == false, "Already approved");
        coins[_coin] = true;
        allCoins.push(IERC20(_coin));
    }

    function setPause(address _coin, bool _pause) external {
        require(msg.sender == governance, "!governance");
        pause[_coin] = _pause;
    }

    function setA(uint _A) external {
        require(msg.sender == governance, "!governance");
        require(_A > 0 && _A <= 1e18, "Invalid A");
        // When A is close to 1, it becomes the fixed price model (x + y = k).
        // When A is close to 0, it degenerates to Uniswap (x * y = k).
        // However, A couldn't be exactly 0 since it will break the f function.
        A = _A;
    }

    function seize(IERC20 token, uint amount) external {
        require(msg.sender == governance, "!governance");
        require(!tokens[address(token)], "can't seize liquidity");

        uint bal = token.balanceOf(address(this));
        require(amount <= bal);

        token.safeTransfer(reservePool, amount);
    }

    uint public fee = 0.99965e18;
    uint public reserveRatio = 1e18;
    uint public constant BASE = 1e18;

    uint public A = 0.7e18;
    uint public count = 0;
    mapping(address => bool) tokens;

    function f(int256 _x, int256 x, int256 y) internal view returns (int256 _y) {
        int256 k;
        int256 c;
        {
            int256 u = x.add(y.mul(int256(A)).div(1e18));
            int256 v = y.add(x.mul(int256(A)).div(1e18));
            k = u.mul(v);
            c = _x.mul(_x).sub(k.mul(1e18).div(int256(A)));
        }

        int256 cst = int256(A).add(int256(1e36).div(int256(A)));
        int256 _b = _x.mul(cst).div(1e18);

        int256 D = _b.mul(_b).sub(c.mul(4));

        require(D >= 0, "!root");

        _y = (-_b).add(D.sqrt()).div(2);
    }

    function collectReserve(IERC20 from, uint input) internal {
        if (reserveRatio > 0) {
            uint _fee = input.mul(BASE.sub(fee)).div(BASE);
            uint _reserve = _fee.mul(reserveRatio).div(BASE);
            from.safeTransfer(reservePool, _reserve);
        }
    }

    // Get all support coins
    function getAllCoins() public view returns (IERC20[] memory) {
        return allCoins;
    }

    // Calculate total pool value in USD
    function calcTotalValue() public view returns (uint value) {
        uint totalValue = uint(0);
        for (uint i = 0; i < allCoins.length; i++) {
            totalValue = totalValue.add(balance(allCoins[i]));
        }
        return totalValue;
    }

    // Calculate _x given x, y, _y
    function getX(int256 output, int256 x, int256 y) internal view returns (int256 input) {
        int256 _y = y.sub(output);
        int256 _x = f(_y, y, x);
        input = _x.sub(x);
    }

    // Calculate _y given x, y, _x
    function getY(int256 input, int256 x, int256 y) internal view returns (int256 output) {
        int256 _x = x.add(input);
        int256 _y = f(_x, x, y);
        output = y.sub(_y);
    }

    // Calculate output given exact input
    function getOutExactIn(IERC20 from, IERC20 to, uint input, int256 x, int256 y) public view returns (uint output) {
        uint inputInUsd = normalize1e18(from, input).mul(normalizer.getPrice(address(from))).div(1e18);
        uint inputAfterFeeInUsd = inputInUsd.mul(fee).div(BASE);

        uint outputInUsd = uint(getY(i(inputAfterFeeInUsd), x, y));

        output = normalize(to, outputInUsd.mul(1e18).div(normalizer.getPrice(address(to))));
    }

    // Calculate input given exact output
    function getInExactOut(IERC20 from, IERC20 to, uint output, int256 x, int256 y) public view returns (uint input) {
        uint outputInUsd = normalize1e18(to, output).mul(normalizer.getPrice(address(to))).div(1e18);

        uint inputBeforeFeeInUsd = uint(getX(i(outputInUsd), x, y));
        uint inputInUsd = inputBeforeFeeInUsd.mul(BASE).div(fee);

        input = normalize(from, inputInUsd.mul(1e18).div(normalizer.getPrice(address(from))));
    }

    // Normalize coin to 1e18
    function normalize1e18(IERC20 token, uint _amount) internal view returns (uint) {
        uint _decimals = ERC20Detailed(address(token)).decimals();
        if (_decimals == uint(18)) {
            return _amount;
        } else {
            return _amount.mul(1e18).div(uint(10)**_decimals);
        }
    }

    // Normalize coin to original decimals
    function normalize(IERC20 token, uint _amount) internal view returns (uint) {
        uint _decimals = ERC20Detailed(address(token)).decimals();
        if (_decimals == uint(18)) {
            return _amount;
        } else {
            return _amount.mul(uint(10)**_decimals).div(1e18);
        }
    }

    // Contract balance of coin normalized to 1e18
    function balance(IERC20 token) public view returns (uint) {
        address _token = address(token);
        uint _balance = IERC20(_token).balanceOf(address(this));
        uint _balanceInUsd = _balance.mul(normalizer.getPrice(_token)).div(1e18);
        return normalize1e18(token, _balanceInUsd);
    }

    // Converter helper to int256
    function i(uint x) public pure returns (int256) {
        int256 value = int256(x);
        require(value >= 0, 'overflow');
        return value;
    }

    function swapExactAmountIn(IERC20 from, IERC20 to, uint input, uint minOutput, uint deadline) external returns (uint output) {
        require(coins[address(from)] == true, "!coin");
        require(pause[address(from)] == false, "pause");
        require(coins[address(to)] == true, "!coin");
        require(pause[address(to)] == false, "pause");
        require(normalizer.getPrice(address(from)) > 0, "zero price");
        require(normalizer.getPrice(address(to)) > 0, "zero price");

        require(block.timestamp <= deadline, "expired");

        output = getOutExactIn(from, to, input, i(balance(from)), i(balance(to)));

        require(balance(to) >= output, "insufficient output liquidity");
        require(output >= minOutput, "slippage");

        emit LOG_SWAP(msg.sender, address(from), address(to), input, output);

        from.safeTransferFrom(msg.sender, address(this), input);
        to.safeTransfer(msg.sender, output);
        collectReserve(from, input);
        return output;
    }

    function swapExactAmountOut(IERC20 from, IERC20 to, uint maxInput, uint output, uint deadline) external returns (uint input) {
        require(coins[address(from)] == true, "!coin");
        require(pause[address(from)] == false, "pause");
        require(coins[address(to)] == true, "!coin");
        require(pause[address(to)] == false, "pause");
        require(normalizer.getPrice(address(from)) > 0, "zero price");
        require(normalizer.getPrice(address(to)) > 0, "zero price");

        require(block.timestamp <= deadline, "expired");
        require(balance(to) >= output, "insufficient output liquidity");

        input = getInExactOut(from, to, output, i(balance(from)), i(balance(to)));

        require(input <= maxInput, "slippage");

        emit LOG_SWAP(msg.sender, address(from), address(to), input, output);

        from.safeTransferFrom(msg.sender, address(this), input);
        to.safeTransfer(msg.sender, output);
        collectReserve(from, input);
        return input;
    }

    function addLiquidityExactIn(IERC20 from, uint input, uint minOutput, uint deadline) external returns (uint output) {
        require(coins[address(from)] == true, "!coin");
        require(pause[address(from)] == false, "pause");
        require(block.timestamp <= deadline, "expired");
        require(input > 0, "zero input");
        require(normalizer.getPrice(address(from)) > 0, "zero price");
        require(normalizer.getPrice(address(this)) > 0, "zero price");

        if (totalSupply() == 0) {
            uint inputAfterFee = input.mul(fee).div(BASE);
            output = normalize1e18(from, inputAfterFee.mul(normalizer.getPrice(address(from))).div(1e18));
        } else {
            output = getOutExactIn(from, this, input, i(balance(from)), i(totalSupply().div(count)));
        }

        require(output >= minOutput, "slippage");

        emit LOG_JOIN(msg.sender, address(from), output);

        from.safeTransferFrom(msg.sender, address(this), input);
        _mint(msg.sender, output);

        if (!tokens[address(from)] && balance(from) > 0) {
            tokens[address(from)] = true;
            count = count.add(1);
        }
    }

    function addLiquidityExactOut(IERC20 from, uint maxInput, uint output, uint deadline) external returns (uint input) {
        require(coins[address(from)] == true, "!coin");
        require(pause[address(from)] == false, "pause");
        require(block.timestamp <= deadline, "expired");
        require(output > 0, "zero output");
        require(normalizer.getPrice(address(from)) > 0, "zero price");
        require(normalizer.getPrice(address(this)) > 0, "zero price");

        if (totalSupply() == 0) {
            uint inputAfterFee = normalize(from, output.mul(1e18).div(normalizer.getPrice(address(from))));
            input = inputAfterFee.mul(BASE).divCeil(fee);
        } else {
            input = getInExactOut(from, this, output, i(balance(from)), i(totalSupply().div(count)));
        }

        require(input <= maxInput, "slippage");

        emit LOG_JOIN(msg.sender, address(from), output);

        from.safeTransferFrom(msg.sender, address(this), input);
        _mint(msg.sender, output);

        if (!tokens[address(from)] && balance(from) > 0) {
            tokens[address(from)] = true;
            count = count.add(1);
        }
    }

    function removeLiquidityExactIn(IERC20 to, uint input, uint minOutput, uint deadline) external returns (uint output) {
        require(block.timestamp <= deadline, "expired");
        require(coins[address(to)] == true, "!coin");
        require(input > 0, "zero input");
        require(normalizer.getPrice(address(this)) > 0, "zero price");
        require(normalizer.getPrice(address(to)) > 0, "zero price");

        output = getOutExactIn(this, to, input, i(totalSupply().div(count)), i(balance(to)));

        require(output >= minOutput, "slippage");

        emit LOG_EXIT(msg.sender, address(to), output);

        _burn(msg.sender, input);
        to.safeTransfer(msg.sender, output);

        if (balance(to) == 0) {
            tokens[address(to)] = false;
            count = count.sub(1);
        }
    }

    function removeLiquidityExactOut(IERC20 to, uint maxInput, uint output, uint deadline) external returns (uint input) {
        require(block.timestamp <= deadline, "expired");
        require(coins[address(to)] == true, "!coin");
        require(output > 0, "zero output");
        require(normalizer.getPrice(address(this)) > 0, "zero price");
        require(normalizer.getPrice(address(to)) > 0, "zero price");

        input = getInExactOut(this, to, output, i(totalSupply().div(count)), i(balance(to)));

        require(input <= maxInput, "slippage");

        emit LOG_EXIT(msg.sender, address(to), output);

        _burn(msg.sender, input);
        to.safeTransfer(msg.sender, output);

        if (balance(to) == 0) {
            tokens[address(to)] = false;
            count = count.sub(1);
        }
    }
}
合同源代码
文件 2 的 3:normalizer.sol
pragma solidity 0.5.17;

import './safeMath.sol';

interface Curve {
    function get_virtual_price() external view returns (uint);
}

interface Yearn {
    function getPricePerFullShare() external view returns (uint);
}

interface UnderlyingToken {
    function decimals() external view returns (uint8);
}

interface Compound {
    function exchangeRateStored() external view returns (uint);
    function underlying() external view returns (address);
}

interface Cream {
    function exchangeRateStored() external view returns (uint);
    function underlying() external view returns (address);
}

contract Normalizer {
    using SafeMath for uint;

    address public governance;
    address public creamY;
    mapping(address => bool) public native;
    mapping(address => bool) public yearn;
    mapping(address => bool) public curve;
    mapping(address => address) public curveSwap;
    mapping(address => bool) public vaults;
    mapping(address => bool) public compound;
    mapping(address => bool) public cream;
    mapping(address => uint) public underlyingDecimals;

    constructor() public {
        governance = msg.sender;

        native[0xdAC17F958D2ee523a2206206994597C13D831ec7] = true; // USDT
        native[0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48] = true; // USDC
        native[0x4Fabb145d64652a948d72533023f6E7A623C7C53] = true; // BUSD
        native[0x0000000000085d4780B73119b644AE5ecd22b376] = true; // TUSD

        yearn[0xACd43E627e64355f1861cEC6d3a6688B31a6F952] = true; // vault yDAI
        yearn[0x37d19d1c4E1fa9DC47bD1eA12f742a0887eDa74a] = true; // vault yTUSD
        yearn[0x597aD1e0c13Bfe8025993D9e79C69E1c0233522e] = true; // vault yUSDC
        yearn[0x2f08119C6f07c006695E079AAFc638b8789FAf18] = true; // vault yUSDT

        yearn[0x16de59092dAE5CcF4A1E6439D611fd0653f0Bd01] = true; // yDAI
        yearn[0xd6aD7a6750A7593E092a9B218d66C0A814a3436e] = true; // yUSDC
        yearn[0x83f798e925BcD4017Eb265844FDDAbb448f1707D] = true; // yUSDT
        yearn[0x73a052500105205d34Daf004eAb301916DA8190f] = true; // yTUSD
        yearn[0xF61718057901F84C4eEC4339EF8f0D86D2B45600] = true; // ySUSD

        yearn[0xC2cB1040220768554cf699b0d863A3cd4324ce32] = true; // bDAI
        yearn[0x26EA744E5B887E5205727f55dFBE8685e3b21951] = true; // bUSDC
        yearn[0xE6354ed5bC4b393a5Aad09f21c46E101e692d447] = true; // bUSDT
        yearn[0x04bC0Ab673d88aE9dbC9DA2380cB6B79C4BCa9aE] = true; // bBUSD

        curve[0x845838DF265Dcd2c412A1Dc9e959c7d08537f8a2] = true; // cCompound
        curveSwap[0x845838DF265Dcd2c412A1Dc9e959c7d08537f8a2] = 0xA2B47E3D5c44877cca798226B7B8118F9BFb7A56;
        curve[0xdF5e0e81Dff6FAF3A7e52BA697820c5e32D806A8] = true; // cYearn
        curveSwap[0xdF5e0e81Dff6FAF3A7e52BA697820c5e32D806A8] = 0x45F783CCE6B7FF23B2ab2D70e416cdb7D6055f51;
        curve[0x3B3Ac5386837Dc563660FB6a0937DFAa5924333B] = true; // cBUSD
        curveSwap[0x3B3Ac5386837Dc563660FB6a0937DFAa5924333B] = 0x79a8C46DeA5aDa233ABaFFD40F3A0A2B1e5A4F27;
        curve[0xC25a3A3b969415c80451098fa907EC722572917F] = true; // cSUSD
        curveSwap[0xC25a3A3b969415c80451098fa907EC722572917F] = 0xA5407eAE9Ba41422680e2e00537571bcC53efBfD;
        curve[0xD905e2eaeBe188fc92179b6350807D8bd91Db0D8] = true; // cPAX
        curveSwap[0xD905e2eaeBe188fc92179b6350807D8bd91Db0D8] = 0x06364f10B501e868329afBc005b3492902d6C763;

        compound[0x5d3a536E4D6DbD6114cc1Ead35777bAB948E3643] = true; // cDAI
        underlyingDecimals[0x5d3a536E4D6DbD6114cc1Ead35777bAB948E3643] = 1e18;
        compound[0x39AA39c021dfbaE8faC545936693aC917d5E7563] = true; // cUSDC
        underlyingDecimals[0x39AA39c021dfbaE8faC545936693aC917d5E7563] = 1e6;
        compound[0xf650C3d88D12dB855b8bf7D11Be6C55A4e07dCC9] = true; // cUSDT
        underlyingDecimals[0xf650C3d88D12dB855b8bf7D11Be6C55A4e07dCC9] = 1e6;

        cream[0x44fbeBd2F576670a6C33f6Fc0B00aA8c5753b322] = true; // crUSDC
        underlyingDecimals[0x44fbeBd2F576670a6C33f6Fc0B00aA8c5753b322] = 1e6;
        cream[0x797AAB1ce7c01eB727ab980762bA88e7133d2157] = true; // crUSDT
        underlyingDecimals[0x797AAB1ce7c01eB727ab980762bA88e7133d2157] = 1e6;
        cream[0x1FF8CDB51219a8838b52E9cAc09b71e591BC998e] = true; // crBUSD
        underlyingDecimals[0x1FF8CDB51219a8838b52E9cAc09b71e591BC998e] = 1e18;
    }

    function setGovernance(address _governance) external {
        require(msg.sender == governance, "!governance");
        governance = _governance;
    }

    function setCreamY(address _creamY) external {
        require(msg.sender == governance, "!governance");
        creamY = _creamY;
    }

    function getPrice(address token) external view returns (uint) {
        if (native[token] || token == creamY) {
            return 1e18;
        } else if (yearn[token]) {
            return Yearn(token).getPricePerFullShare();
        } else if (curve[token]) {
            return Curve(curveSwap[token]).get_virtual_price();
        } else if (compound[token]) {
            return getCompoundPrice(token);
        } else if (cream[token]) {
            return getCreamPrice(token);
        } else {
            return uint(0);
        }
    }

    function getCompoundPrice(address token) public view returns (uint) {
        address underlying = Compound(token).underlying();
        uint8 decimals = UnderlyingToken(underlying).decimals();
        return Compound(token).exchangeRateStored().mul(1e8).div(uint(10) ** decimals);
    }

    function getCreamPrice(address token) public view returns (uint) {
        address underlying = Cream(token).underlying();
        uint8 decimals = UnderlyingToken(underlying).decimals();
        return Cream(token).exchangeRateStored().mul(1e8).div(uint(10) ** decimals);
    }
}
合同源代码
文件 3 的 3:safeMath.sol
pragma solidity 0.5.17;

library SafeMath {
    function add(uint a, uint b) internal pure returns (uint) {
        uint c = a + b;
        require(c >= a, "SafeMath: addition overflow");

        return c;
    }
    function sub(uint a, uint b) internal pure returns (uint) {
        return sub(a, b, "SafeMath: subtraction overflow");
    }
    function sub(uint a, uint b, string memory errorMessage) internal pure returns (uint) {
        require(b <= a, errorMessage);
        uint c = a - b;

        return c;
    }
    function mul(uint a, uint b) internal pure returns (uint) {
        if (a == 0) {
            return 0;
        }

        uint c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");

        return c;
    }
    function div(uint a, uint b) internal pure returns (uint) {
        return div(a, b, "SafeMath: division by zero");
    }
    function div(uint a, uint b, string memory errorMessage) internal pure returns (uint) {
        // Solidity only automatically asserts when dividing by 0
        require(b > 0, errorMessage);
        uint c = a / b;

        return c;
    }
    function divCeil(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b > 0);
        uint256 c = a / b;
        if(a % b != 0)
            c = c + 1;
        return c;
    }
}
设置
{
  "compilationTarget": {
    "creamY.sol": "CreamY"
  },
  "evmVersion": "istanbul",
  "libraries": {},
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "remappings": []
}
ABI
[{"inputs":[{"internalType":"address","name":"_normalizer","type":"address"},{"internalType":"address","name":"_reservePool","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"tokenOut","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenAmountOut","type":"uint256"}],"name":"LOG_EXIT","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"tokenIn","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenAmountIn","type":"uint256"}],"name":"LOG_JOIN","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"tokenIn","type":"address"},{"indexed":true,"internalType":"address","name":"tokenOut","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenAmountIn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"tokenAmountOut","type":"uint256"}],"name":"LOG_SWAP","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"constant":true,"inputs":[],"name":"A","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"BASE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"contract IERC20","name":"from","type":"address"},{"internalType":"uint256","name":"input","type":"uint256"},{"internalType":"uint256","name":"minOutput","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"addLiquidityExactIn","outputs":[{"internalType":"uint256","name":"output","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"contract IERC20","name":"from","type":"address"},{"internalType":"uint256","name":"maxInput","type":"uint256"},{"internalType":"uint256","name":"output","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"addLiquidityExactOut","outputs":[{"internalType":"uint256","name":"input","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"allCoins","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_coin","type":"address"}],"name":"approveCoins","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"}],"name":"balance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"calcTotalValue","outputs":[{"internalType":"uint256","name":"value","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"coins","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"count","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"fee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getAllCoins","outputs":[{"internalType":"contract IERC20[]","name":"","type":"address[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"contract IERC20","name":"from","type":"address"},{"internalType":"contract IERC20","name":"to","type":"address"},{"internalType":"uint256","name":"output","type":"uint256"},{"internalType":"int256","name":"x","type":"int256"},{"internalType":"int256","name":"y","type":"int256"}],"name":"getInExactOut","outputs":[{"internalType":"uint256","name":"input","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"contract IERC20","name":"from","type":"address"},{"internalType":"contract IERC20","name":"to","type":"address"},{"internalType":"uint256","name":"input","type":"uint256"},{"internalType":"int256","name":"x","type":"int256"},{"internalType":"int256","name":"y","type":"int256"}],"name":"getOutExactIn","outputs":[{"internalType":"uint256","name":"output","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"governance","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"x","type":"uint256"}],"name":"i","outputs":[{"internalType":"int256","name":"","type":"int256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"normalizer","outputs":[{"internalType":"contract Normalizer","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"pause","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"contract IERC20","name":"to","type":"address"},{"internalType":"uint256","name":"input","type":"uint256"},{"internalType":"uint256","name":"minOutput","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"removeLiquidityExactIn","outputs":[{"internalType":"uint256","name":"output","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"contract IERC20","name":"to","type":"address"},{"internalType":"uint256","name":"maxInput","type":"uint256"},{"internalType":"uint256","name":"output","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"removeLiquidityExactOut","outputs":[{"internalType":"uint256","name":"input","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"reservePool","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"reserveRatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"seize","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"_A","type":"uint256"}],"name":"setA","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"_fee","type":"uint256"},{"internalType":"uint256","name":"_reserveRatio","type":"uint256"}],"name":"setFees","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_governance","type":"address"}],"name":"setGovernance","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_normalizer","type":"address"}],"name":"setNormalizer","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_coin","type":"address"},{"internalType":"bool","name":"_pause","type":"bool"}],"name":"setPause","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_reservePool","type":"address"}],"name":"setReservePool","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"contract IERC20","name":"from","type":"address"},{"internalType":"contract IERC20","name":"to","type":"address"},{"internalType":"uint256","name":"input","type":"uint256"},{"internalType":"uint256","name":"minOutput","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactAmountIn","outputs":[{"internalType":"uint256","name":"output","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"contract IERC20","name":"from","type":"address"},{"internalType":"contract IERC20","name":"to","type":"address"},{"internalType":"uint256","name":"maxInput","type":"uint256"},{"internalType":"uint256","name":"output","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactAmountOut","outputs":[{"internalType":"uint256","name":"input","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"}]